summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp118
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp7
-rw-r--r--lib/Sema/CoroutineStmtBuilder.h7
-rw-r--r--lib/Sema/DeclSpec.cpp83
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp7
-rw-r--r--lib/Sema/IdentifierResolver.cpp7
-rw-r--r--lib/Sema/JumpDiagnostics.cpp121
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp7
-rw-r--r--lib/Sema/OpenCLBuiltins.td296
-rw-r--r--lib/Sema/ParsedAttr.cpp7
-rw-r--r--lib/Sema/Scope.cpp11
-rw-r--r--lib/Sema/ScopeInfo.cpp63
-rw-r--r--lib/Sema/Sema.cpp433
-rw-r--r--lib/Sema/SemaAccess.cpp10
-rw-r--r--lib/Sema/SemaAttr.cpp22
-rw-r--r--lib/Sema/SemaCUDA.cpp262
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp45
-rw-r--r--lib/Sema/SemaCast.cpp219
-rw-r--r--lib/Sema/SemaChecking.cpp829
-rw-r--r--lib/Sema/SemaCodeComplete.cpp904
-rw-r--r--lib/Sema/SemaConsumer.cpp7
-rw-r--r--lib/Sema/SemaCoroutine.cpp102
-rw-r--r--lib/Sema/SemaDecl.cpp1331
-rw-r--r--lib/Sema/SemaDeclAttr.cpp700
-rw-r--r--lib/Sema/SemaDeclCXX.cpp623
-rw-r--r--lib/Sema/SemaDeclObjC.cpp121
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp42
-rw-r--r--lib/Sema/SemaExpr.cpp2122
-rw-r--r--lib/Sema/SemaExprCXX.cpp368
-rw-r--r--lib/Sema/SemaExprMember.cpp101
-rw-r--r--lib/Sema/SemaExprObjC.cpp92
-rw-r--r--lib/Sema/SemaFixItUtils.cpp7
-rw-r--r--lib/Sema/SemaInit.cpp480
-rw-r--r--lib/Sema/SemaLambda.cpp407
-rw-r--r--lib/Sema/SemaLookup.cpp390
-rw-r--r--lib/Sema/SemaModule.cpp710
-rw-r--r--lib/Sema/SemaObjCProperty.cpp27
-rw-r--r--lib/Sema/SemaOpenMP.cpp2385
-rw-r--r--lib/Sema/SemaOverload.cpp762
-rw-r--r--lib/Sema/SemaPseudoObject.cpp44
-rw-r--r--lib/Sema/SemaStmt.cpp149
-rw-r--r--lib/Sema/SemaStmtAsm.cpp180
-rw-r--r--lib/Sema/SemaStmtAttr.cpp77
-rw-r--r--lib/Sema/SemaTemplate.cpp609
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp54
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp129
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp578
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp69
-rw-r--r--lib/Sema/SemaType.cpp508
-rw-r--r--lib/Sema/TreeTransform.h733
-rw-r--r--lib/Sema/TypeLocBuilder.cpp7
-rw-r--r--lib/Sema/TypeLocBuilder.h7
52 files changed, 12032 insertions, 5347 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index c818d40c7771..ce01909f1858 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1,9 +1,8 @@
//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -250,6 +249,10 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
CFG *cfg = AC.getCFG();
if (!cfg) return;
+ // If the exit block is unreachable, skip processing the function.
+ if (cfg->getExit().pred_empty())
+ return;
+
// Emit diagnostic if a recursive function call is detected for all paths.
if (checkForRecursiveFunctionCall(FD, cfg))
S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function);
@@ -395,7 +398,8 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
for (const auto *B : *cfg) {
if (!live[B->getBlockID()]) {
if (B->pred_begin() == B->pred_end()) {
- if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator()))
+ const Stmt *Term = B->getTerminatorStmt();
+ if (Term && isa<CXXTryStmt>(Term))
// When not adding EH edges from calls, catch clauses
// can otherwise seem dead. Avoid noting them as dead.
count += reachable_code::ScanReachableFromBlock(B, live);
@@ -443,7 +447,8 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
// No more CFGElements in the block?
if (ri == re) {
- if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
+ const Stmt *Term = B.getTerminatorStmt();
+ if (Term && isa<CXXTryStmt>(Term)) {
HasAbnormalEdge = true;
continue;
}
@@ -615,7 +620,7 @@ struct CheckFallThroughDiagnostics {
/// of a noreturn function. We assume that functions and blocks not marked
/// noreturn will return.
static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
- const BlockExpr *blkExpr,
+ QualType BlockType,
const CheckFallThroughDiagnostics &CD,
AnalysisDeclContext &AC,
sema::FunctionScopeInfo *FSI) {
@@ -636,9 +641,8 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
else if (isa<BlockDecl>(D)) {
- QualType BlockTy = blkExpr->getType();
if (const FunctionType *FT =
- BlockTy->getPointeeType()->getAs<FunctionType>()) {
+ BlockType->getPointeeType()->getAs<FunctionType>()) {
if (FT->getReturnType()->isVoidType())
ReturnsVoid = true;
if (FT->getNoReturnAttr())
@@ -995,7 +999,8 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>())
S.Diag(BE->getBeginLoc(),
diag::warn_uninit_byref_blockvar_captured_by_block)
- << VD->getDeclName();
+ << VD->getDeclName()
+ << VD->getType().getQualifiers().hasObjCLifetime();
else
DiagUninitUse(S, VD, Use, true);
}
@@ -1073,7 +1078,7 @@ namespace {
BlockQueue.pop_front();
if (!P) continue;
- const Stmt *Term = P->getTerminator();
+ const Stmt *Term = P->getTerminatorStmt();
if (Term && isa<SwitchStmt>(Term))
continue; // Switch statement, good.
@@ -1171,7 +1176,7 @@ namespace {
}
static const Stmt *getLastStmt(const CFGBlock &B) {
- if (const Stmt *Term = B.getTerminator())
+ if (const Stmt *Term = B.getTerminatorStmt())
return Term;
for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(),
ElemEnd = B.rend();
@@ -1277,11 +1282,11 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
if (L.isMacroID())
continue;
if (S.getLangOpts().CPlusPlus11) {
- const Stmt *Term = B->getTerminator();
+ const Stmt *Term = B->getTerminatorStmt();
// Skip empty cases.
while (B->empty() && !Term && B->succ_size() == 1) {
B = *B->succ_begin();
- Term = B->getTerminator();
+ Term = B->getTerminatorStmt();
}
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
@@ -1639,15 +1644,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
return ONS;
}
- // Helper functions
- void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName,
- SourceLocation Loc) {
- // Gracefully handle rare cases when the analysis can't get a more
- // precise source location.
- if (!Loc.isValid())
- Loc = FunLocation;
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName);
- Warnings.emplace_back(std::move(Warning), getNotes());
+ OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) {
+ return LocLocked.isValid()
+ ? getNotes(PartialDiagnosticAt(
+ LocLocked, S.PDiag(diag::note_locked_here) << Kind))
+ : getNotes();
}
public:
@@ -1678,22 +1679,34 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
void handleUnmatchedUnlock(StringRef Kind, Name LockName,
SourceLocation Loc) override {
- warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc);
- }
-
- void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
- LockKind Expected, LockKind Received,
- SourceLocation Loc) override {
if (Loc.isInvalid())
Loc = FunLocation;
- PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch)
- << Kind << LockName << Received
- << Expected);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock)
+ << Kind << LockName);
Warnings.emplace_back(std::move(Warning), getNotes());
}
- void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override {
- warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc);
+ void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
+ LockKind Expected, LockKind Received,
+ SourceLocation LocLocked,
+ SourceLocation LocUnlock) override {
+ if (LocUnlock.isInvalid())
+ LocUnlock = FunLocation;
+ PartialDiagnosticAt Warning(
+ LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch)
+ << Kind << LockName << Received << Expected);
+ Warnings.emplace_back(std::move(Warning),
+ makeLockedHereNote(LocLocked, Kind));
+ }
+
+ void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
+ SourceLocation LocDoubleLock) override {
+ if (LocDoubleLock.isInvalid())
+ LocDoubleLock = FunLocation;
+ PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock)
+ << Kind << LockName);
+ Warnings.emplace_back(std::move(Warning),
+ makeLockedHereNote(LocLocked, Kind));
}
void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
@@ -1720,13 +1733,8 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind
<< LockName);
- if (LocLocked.isValid()) {
- PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)
- << Kind);
- Warnings.emplace_back(std::move(Warning), getNotes(Note));
- return;
- }
- Warnings.emplace_back(std::move(Warning), getNotes());
+ Warnings.emplace_back(std::move(Warning),
+ makeLockedHereNote(LocLocked, Kind));
}
void handleExclusiveAndShared(StringRef Kind, Name LockName,
@@ -2003,7 +2011,7 @@ static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {
void clang::sema::
AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
sema::FunctionScopeInfo *fscope,
- const Decl *D, const BlockExpr *blkExpr) {
+ const Decl *D, QualType BlockType) {
// We avoid doing analysis-based warnings when there are errors for
// two reasons:
@@ -2082,16 +2090,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Register the expressions with the CFGBuilder.
for (const auto &D : fscope->PossiblyUnreachableDiags) {
- if (D.stmt)
- AC.registerForcedBlockExpression(D.stmt);
+ for (const Stmt *S : D.Stmts)
+ AC.registerForcedBlockExpression(S);
}
if (AC.getCFG()) {
analyzed = true;
for (const auto &D : fscope->PossiblyUnreachableDiags) {
- bool processed = false;
- if (D.stmt) {
- const CFGBlock *block = AC.getBlockForRegisteredExpression(D.stmt);
+ bool AllReachable = true;
+ for (const Stmt *S : D.Stmts) {
+ const CFGBlock *block = AC.getBlockForRegisteredExpression(S);
CFGReverseBlockReachabilityAnalysis *cra =
AC.getCFGReachablityAnalysis();
// FIXME: We should be able to assert that block is non-null, but
@@ -2099,15 +2107,17 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// edge cases; see test/Sema/vla-2.c.
if (block && cra) {
// Can this block be reached from the entrance?
- if (cra->isReachable(&AC.getCFG()->getEntry(), block))
- S.Diag(D.Loc, D.PD);
- processed = true;
+ if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) {
+ AllReachable = false;
+ break;
+ }
}
+ // If we cannot map to a basic block, assume the statement is
+ // reachable.
}
- if (!processed) {
- // Emit the warning anyway if we cannot map to a basic block.
+
+ if (AllReachable)
S.Diag(D.Loc, D.PD);
- }
}
}
@@ -2127,7 +2137,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
: (fscope->isCoroutine()
? CheckFallThroughDiagnostics::MakeForCoroutine(D)
: CheckFallThroughDiagnostics::MakeForFunction(D)));
- CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC, fscope);
+ CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope);
}
// Warning: check for unreachable code
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 92e65c4b819b..b88ff9dd64cd 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -1,9 +1,8 @@
//===- CodeCompleteConsumer.cpp - Code Completion Interface ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/CoroutineStmtBuilder.h b/lib/Sema/CoroutineStmtBuilder.h
index d15cf0b756e7..42499a32fc16 100644
--- a/lib/Sema/CoroutineStmtBuilder.h
+++ b/lib/Sema/CoroutineStmtBuilder.h
@@ -1,9 +1,8 @@
//===- CoroutineStmtBuilder.h - Implicit coroutine stmt builder -*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===//
//
// This file defines CoroutineStmtBuilder, a class for building the implicit
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 8b002dac1343..77e5eb095693 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -1,9 +1,8 @@
//===--- DeclSpec.cpp - Declaration Specifier Semantic Analysis -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -446,7 +445,7 @@ unsigned DeclSpec::getParsedSpecifiers() const {
if (hasTypeSpecifier())
Res |= PQ_TypeSpecifier;
- if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified ||
+ if (FS_inline_specified || FS_virtual_specified || hasExplicitSpecifier() ||
FS_noreturn_specified || FS_forceinline_specified)
Res |= PQ_FunctionSpecifier;
return Res;
@@ -565,6 +564,15 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
llvm_unreachable("Unknown typespec!");
}
+const char *DeclSpec::getSpecifierName(ConstexprSpecKind C) {
+ switch (C) {
+ case CSK_unspecified: return "unspecified";
+ case CSK_constexpr: return "constexpr";
+ case CSK_consteval: return "consteval";
+ }
+ llvm_unreachable("Unknown ConstexprSpecKind");
+}
+
const char *DeclSpec::getSpecifierName(TQ T) {
switch (T) {
case DeclSpec::TQ_unspecified: return "unspecified";
@@ -588,7 +596,6 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
// these storage-class specifiers.
// OpenCL v1.2 s6.8 changes this to "The auto and register storage-class
// specifiers are not supported."
- // OpenCL C++ v1.0 s2.9 restricts register.
if (S.getLangOpts().OpenCL &&
!S.getOpenCLOptions().isEnabled("cl_clang_storage_class_specifiers")) {
switch (SC) {
@@ -707,6 +714,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
const PrintingPolicy &Policy) {
assert(isTypeRep(T) && "T does not store a type");
assert(Rep && "no type provided!");
+ if (TypeSpecType == TST_error)
+ return false;
if (TypeSpecType != TST_unspecified) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
@@ -727,6 +736,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const PrintingPolicy &Policy) {
assert(isExprRep(T) && "T does not store an expr");
assert(Rep && "no expression provided!");
+ if (TypeSpecType == TST_error)
+ return false;
if (TypeSpecType != TST_unspecified) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
@@ -757,6 +768,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
assert(isDeclRep(T) && "T does not store a decl");
// Unlike the other cases, we don't assert that we actually get a decl.
+ if (TypeSpecType == TST_error)
+ return false;
if (TypeSpecType != TST_unspecified) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
@@ -776,6 +789,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const PrintingPolicy &Policy) {
assert(!isDeclRep(T) && !isTypeRep(T) && !isExprRep(T) &&
"rep required for these type-spec kinds!");
+ if (TypeSpecType == TST_error)
+ return false;
if (TypeSpecType != TST_unspecified) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
@@ -808,6 +823,8 @@ bool DeclSpec::SetTypeSpecSat(SourceLocation Loc, const char *&PrevSpec,
bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy) {
+ if (TypeSpecType == TST_error)
+ return false;
if (TypeSpecType != TST_unspecified) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_vector_decl_spec_combination;
@@ -821,7 +838,8 @@ bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy) {
-
+ if (TypeSpecType == TST_error)
+ return false;
if (TypeSpecType != TST_unspecified) {
PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
@@ -837,6 +855,8 @@ bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc,
bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy) {
+ if (TypeSpecType == TST_error)
+ return false;
if (!TypeAltiVecVector || TypeAltiVecPixel ||
(TypeSpecType != TST_unspecified)) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
@@ -852,6 +872,8 @@ bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
bool DeclSpec::SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy) {
+ if (TypeSpecType == TST_error)
+ return false;
if (!TypeAltiVecVector || TypeAltiVecBool ||
(TypeSpecType != TST_unspecified)) {
PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
@@ -945,17 +967,24 @@ bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc,
}
bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
- const char *&PrevSpec,
- unsigned &DiagID) {
+ const char *&PrevSpec, unsigned &DiagID,
+ ExplicitSpecifier ExplicitSpec,
+ SourceLocation CloseParenLoc) {
+ assert((ExplicitSpec.getKind() == ExplicitSpecKind::ResolvedTrue ||
+ ExplicitSpec.getExpr()) &&
+ "invalid ExplicitSpecifier");
// 'explicit explicit' is ok, but warn as this is likely not what the user
// intended.
- if (FS_explicit_specified) {
- DiagID = diag::warn_duplicate_declspec;
+ if (hasExplicitSpecifier()) {
+ DiagID = (ExplicitSpec.getExpr() || FS_explicit_specifier.getExpr())
+ ? diag::err_duplicate_declspec
+ : diag::ext_warn_duplicate_declspec;
PrevSpec = "explicit";
return true;
}
- FS_explicit_specified = true;
+ FS_explicit_specifier = ExplicitSpec;
FS_explicitLoc = Loc;
+ FS_explicitCloseParenLoc = CloseParenLoc;
return false;
}
@@ -1004,16 +1033,17 @@ bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
-bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
+bool DeclSpec::SetConstexprSpec(ConstexprSpecKind ConstexprKind,
+ SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
- // 'constexpr constexpr' is ok, but warn as this is likely not what the user
- // intended.
- if (Constexpr_specified) {
+ if (getConstexprSpecifier() != CSK_unspecified) {
+ if (getConstexprSpecifier() == CSK_consteval || ConstexprKind == CSK_consteval)
+ return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec, DiagID);
DiagID = diag::warn_duplicate_declspec;
PrevSpec = "constexpr";
return true;
}
- Constexpr_specified = true;
+ ConstexprSpecifier = ConstexprKind;
ConstexprLoc = Loc;
return false;
}
@@ -1034,7 +1064,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
- // Check the type specifier components first.
+ // Check the type specifier components first. No checking for an invalid
+ // type.
+ if (TypeSpecType == TST_error)
+ return;
// If decltype(auto) is used, no other type specifiers are permitted.
if (TypeSpecType == TST_decltype_auto &&
@@ -1256,9 +1289,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
else if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32)
S.Diag(TSTLoc, diag::warn_cxx98_compat_unicode_type)
<< (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
- if (Constexpr_specified)
+ if (getConstexprSpecifier() == CSK_constexpr)
S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr);
-
+ if (getConstexprSpecifier() == CSK_consteval)
+ S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval);
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
// of a friend declaration.
@@ -1294,23 +1328,26 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// The explicit specifier shall be used only in the declaration of
// a constructor or conversion function within its class
// definition;
- if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) {
+ if (isFriendSpecified() && (isVirtualSpecified() || hasExplicitSpecifier())) {
StringRef Keyword;
+ FixItHint Hint;
SourceLocation SCLoc;
if (isVirtualSpecified()) {
Keyword = "virtual";
SCLoc = getVirtualSpecLoc();
+ Hint = FixItHint::CreateRemoval(SCLoc);
} else {
Keyword = "explicit";
SCLoc = getExplicitSpecLoc();
+ Hint = FixItHint::CreateRemoval(getExplicitSpecRange());
}
- FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
S.Diag(SCLoc, diag::err_friend_decl_spec)
<< Keyword << Hint;
- FS_virtual_specified = FS_explicit_specified = false;
+ FS_virtual_specified = false;
+ FS_explicit_specifier = ExplicitSpecifier();
FS_virtualLoc = FS_explicitLoc = SourceLocation();
}
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index a064e492c098..cb2721b92090 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -1,9 +1,8 @@
//===- DelayedDiagnostic.cpp - Delayed declarator diagnostics -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index b439f7255728..333f4d70986a 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -1,9 +1,8 @@
//===- IdentifierResolver.cpp - Lexical Scope Name lookup -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index a7495e8e0482..c8743df90e34 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -1,9 +1,8 @@
//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -66,8 +65,10 @@ class JumpScopeChecker {
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
SmallVector<Stmt*, 16> Jumps;
- SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
+ SmallVector<Stmt*, 4> IndirectJumps;
+ SmallVector<Stmt*, 4> AsmJumps;
SmallVector<LabelDecl*, 4> IndirectJumpTargets;
+ SmallVector<LabelDecl*, 4> AsmJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
@@ -77,10 +78,10 @@ private:
void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
void VerifyJumps();
- void VerifyIndirectJumps();
+ void VerifyIndirectOrAsmJumps(bool IsAsmGoto);
void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
- void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
- LabelDecl *Target, unsigned TargetScope);
+ void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
+ unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
unsigned JumpDiag, unsigned JumpDiagWarning,
unsigned JumpDiagCXX98Compat);
@@ -104,7 +105,8 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
// Check that all jumps we saw are kosher.
VerifyJumps();
- VerifyIndirectJumps();
+ VerifyIndirectOrAsmJumps(false);
+ VerifyIndirectOrAsmJumps(true);
}
/// GetDeepestCommonScope - Finds the innermost scope enclosing the
@@ -317,7 +319,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
}
LabelAndGotoScopes[S] = ParentScope;
- IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
+ IndirectJumps.push_back(S);
break;
case Stmt::SwitchStmtClass:
@@ -340,6 +342,18 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
Jumps.push_back(S);
break;
+ case Stmt::GCCAsmStmtClass:
+ if (auto *GS = dyn_cast<GCCAsmStmt>(S))
+ if (GS->isAsmGoto()) {
+ // Remember both what scope a goto is in as well as the fact that we
+ // have it. This makes the second scan not have to walk the AST again.
+ LabelAndGotoScopes[S] = ParentScope;
+ AsmJumps.push_back(GS);
+ for (auto *E : GS->labels())
+ AsmJumpTargets.push_back(E->getLabel());
+ }
+ break;
+
case Stmt::IfStmtClass: {
IfStmt *IS = cast<IfStmt>(S);
if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck()))
@@ -630,14 +644,13 @@ void JumpScopeChecker::VerifyJumps() {
}
}
-/// VerifyIndirectJumps - Verify whether any possible indirect jump
-/// might cross a protection boundary. Unlike direct jumps, indirect
-/// jumps count cleanups as protection boundaries: since there's no
-/// way to know where the jump is going, we can't implicitly run the
-/// right cleanups the way we can with direct jumps.
-///
-/// Thus, an indirect jump is "trivial" if it bypasses no
-/// initializations and no teardowns. More formally, an indirect jump
+/// VerifyIndirectOrAsmJumps - Verify whether any possible indirect goto or
+/// asm goto jump might cross a protection boundary. Unlike direct jumps,
+/// indirect or asm goto jumps count cleanups as protection boundaries:
+/// since there's no way to know where the jump is going, we can't implicitly
+/// run the right cleanups the way we can with direct jumps.
+/// Thus, an indirect/asm jump is "trivial" if it bypasses no
+/// initializations and no teardowns. More formally, an indirect/asm jump
/// from A to B is trivial if the path out from A to DCA(A,B) is
/// trivial and the path in from DCA(A,B) to B is trivial, where
/// DCA(A,B) is the deepest common ancestor of A and B.
@@ -649,36 +662,41 @@ void JumpScopeChecker::VerifyJumps() {
/// Under these definitions, this function checks that the indirect
/// jump between A and B is trivial for every indirect goto statement A
/// and every label B whose address was taken in the function.
-void JumpScopeChecker::VerifyIndirectJumps() {
- if (IndirectJumps.empty()) return;
-
+void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
+ SmallVector<Stmt*, 4> GotoJumps = IsAsmGoto ? AsmJumps : IndirectJumps;
+ if (GotoJumps.empty())
+ return;
+ SmallVector<LabelDecl *, 4> JumpTargets =
+ IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets;
// If there aren't any address-of-label expressions in this function,
// complain about the first indirect goto.
- if (IndirectJumpTargets.empty()) {
- S.Diag(IndirectJumps[0]->getGotoLoc(),
+ if (JumpTargets.empty()) {
+ assert(!IsAsmGoto &&"only indirect goto can get here");
+ S.Diag(GotoJumps[0]->getBeginLoc(),
diag::err_indirect_goto_without_addrlabel);
return;
}
-
// Collect a single representative of every scope containing an
- // indirect goto. For most code bases, this substantially cuts
+ // indirect or asm goto. For most code bases, this substantially cuts
// down on the number of jump sites we'll have to consider later.
- typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope;
+ typedef std::pair<unsigned, Stmt*> JumpScope;
SmallVector<JumpScope, 32> JumpScopes;
{
- llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap;
- for (SmallVectorImpl<IndirectGotoStmt*>::iterator
- I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
- IndirectGotoStmt *IG = *I;
+ llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
+ for (SmallVectorImpl<Stmt *>::iterator I = GotoJumps.begin(),
+ E = GotoJumps.end();
+ I != E; ++I) {
+ Stmt *IG = *I;
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
continue;
unsigned IGScope = LabelAndGotoScopes[IG];
- IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
+ Stmt *&Entry = JumpScopesMap[IGScope];
if (!Entry) Entry = IG;
}
JumpScopes.reserve(JumpScopesMap.size());
- for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator
- I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I)
+ for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(),
+ E = JumpScopesMap.end();
+ I != E; ++I)
JumpScopes.push_back(*I);
}
@@ -686,8 +704,8 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// label whose address was taken somewhere in the function.
// For most code bases, there will be only one such scope.
llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
- for (SmallVectorImpl<LabelDecl*>::iterator
- I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
+ for (SmallVectorImpl<LabelDecl *>::iterator I = JumpTargets.begin(),
+ E = JumpTargets.end();
I != E; ++I) {
LabelDecl *TheLabel = *I;
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
@@ -764,7 +782,7 @@ void JumpScopeChecker::VerifyIndirectJumps() {
// Only diagnose if we didn't find something.
if (IsReachable) continue;
- DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
+ DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope);
}
}
}
@@ -785,12 +803,15 @@ static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
}
/// Produce primary diagnostic for an indirect jump statement.
-static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
- LabelDecl *Target, bool &Diagnosed) {
+static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,
+ LabelDecl *Target, bool &Diagnosed) {
if (Diagnosed)
return;
- S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+ bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
+ S.Diag(Jump->getBeginLoc(), diag::err_indirect_goto_in_protected_scope)
+ << IsAsmGoto;
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
+ << IsAsmGoto;
Diagnosed = true;
}
@@ -804,10 +825,9 @@ void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
}
/// Diagnose an indirect jump which is known to cross scopes.
-void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
- unsigned JumpScope,
- LabelDecl *Target,
- unsigned TargetScope) {
+void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
+ LabelDecl *Target,
+ unsigned TargetScope) {
if (CHECK_PERMISSIVE(JumpScope == TargetScope))
return;
@@ -817,7 +837,7 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
// Walk out the scope chain until we reach the common ancestor.
for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
if (Scopes[I].OutDiag) {
- DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
+ DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
}
@@ -828,15 +848,18 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
ToScopesCXX98Compat.push_back(I);
else if (Scopes[I].InDiag) {
- DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
+ DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
}
// Diagnose this jump if it would be ill-formed in C++98.
if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
- S.Diag(Jump->getGotoLoc(),
- diag::warn_cxx98_compat_indirect_goto_in_protected_scope);
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
+ bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
+ S.Diag(Jump->getBeginLoc(),
+ diag::warn_cxx98_compat_indirect_goto_in_protected_scope)
+ << IsAsmGoto;
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
+ << IsAsmGoto;
NoteJumpIntoScopes(ToScopesCXX98Compat);
}
}
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index 50808effe007..b0aa67454a7b 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -1,9 +1,8 @@
//===--- MultiplexExternalSemaSource.cpp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/OpenCLBuiltins.td b/lib/Sema/OpenCLBuiltins.td
new file mode 100644
index 000000000000..7e37e55dbafa
--- /dev/null
+++ b/lib/Sema/OpenCLBuiltins.td
@@ -0,0 +1,296 @@
+//==--- OpenCLBuiltins.td - OpenCL builtin declarations -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains TableGen definitions for OpenCL builtin function
+// declarations. In case of an unresolved function name in OpenCL, Clang will
+// check for a function described in this file when -fdeclare-opencl-builtins
+// is specified.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Definitions of miscellaneous basic entities.
+//===----------------------------------------------------------------------===//
+// Versions of OpenCL
+class Version<int _Version> {
+ int Version = _Version;
+}
+def CL10: Version<100>;
+def CL11: Version<110>;
+def CL12: Version<120>;
+def CL20: Version<200>;
+
+// Address spaces
+// Pointer types need to be assigned an address space.
+class AddressSpace<string _AS> {
+ string AddrSpace = _AS;
+}
+def default_as : AddressSpace<"clang::LangAS::Default">;
+def private_as : AddressSpace<"clang::LangAS::opencl_private">;
+def global_as : AddressSpace<"clang::LangAS::opencl_global">;
+def constant_as : AddressSpace<"clang::LangAS::opencl_constant">;
+def local_as : AddressSpace<"clang::LangAS::opencl_local">;
+def generic_as : AddressSpace<"clang::LangAS::opencl_generic">;
+
+
+// Qualified Type. Allow to retrieve one ASTContext QualType.
+class QualType<string _Name> {
+ // Name of the field or function in a clang::ASTContext
+ // E.g. Name="IntTy" for the int type, and "getIntPtrType()" for an intptr_t
+ string Name = _Name;
+}
+
+// Helper class to store type access qualifiers (volatile, const, ...).
+class Qualifier<string _QualName> {
+ string QualName = _QualName;
+}
+
+//===----------------------------------------------------------------------===//
+// OpenCL C classes for types
+//===----------------------------------------------------------------------===//
+// OpenCL types (int, float, ...)
+class Type<string _Name, QualType _QTName> {
+ // Name of the Type
+ string Name = _Name;
+ // QualType associated with this type
+ QualType QTName = _QTName;
+ // Size of the vector (if applicable)
+ int VecWidth = 0;
+ // Is pointer
+ bit IsPointer = 0;
+ // List of qualifiers associated with the type (volatile, ...)
+ list<Qualifier> QualList = [];
+ // Address space
+ string AddrSpace = "clang::LangAS::Default";
+ // Access qualifier. Must be one of ("RO", "WO", "RW").
+ string AccessQualifier = "";
+}
+
+// OpenCL vector types (e.g. int2, int3, int16, float8, ...)
+class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
+ int VecWidth = _VecWidth;
+}
+
+// OpenCL pointer types (e.g. int*, float*, ...)
+class PointerType<Type _Ty, AddressSpace _AS = global_as> :
+ Type<_Ty.Name, _Ty.QTName> {
+ bit IsPointer = 1;
+ string AddrSpace = _AS.AddrSpace;
+}
+
+// OpenCL image types (e.g. image2d_t, ...)
+class ImageType<Type _Ty, QualType _QTName, string _AccessQualifier> :
+ Type<_Ty.Name, _QTName> {
+ let AccessQualifier = _AccessQualifier;
+}
+
+//===----------------------------------------------------------------------===//
+// OpenCL C class for builtin functions
+//===----------------------------------------------------------------------===//
+class Builtin<string _Name, list<Type> _Signature> {
+ // Name of the builtin function
+ string Name = _Name;
+ // List of types used by the function. The first one is the return type and
+ // the following are the arguments. The list must have at least one element
+ // (the return type).
+ list<Type> Signature = _Signature;
+ // OpenCL Extension to which the function belongs (cl_khr_subgroups, ...)
+ string Extension = "";
+ // OpenCL Version to which the function belongs (CL10, ...)
+ Version Version = CL10;
+}
+
+//===----------------------------------------------------------------------===//
+// Multiclass definitions
+//===----------------------------------------------------------------------===//
+// multiclass BifN: Creates Builtin class instances for OpenCL builtin
+// functions with N arguments.
+// _Name : Name of the function
+// _Signature : Signature of the function (list of the Type used by the
+// function, the first one being the return type).
+// _IsVector : List of bit indicating if the type in the _Signature at the
+// same index is to be a vector in the multiple overloads. The
+// list must have at least one non-zero value.
+multiclass Bif0<string _Name, list<Type> _Signature, list<bit> _IsVector> {
+ def : Builtin<_Name, _Signature>;
+ foreach v = [2, 3, 4, 8, 16] in {
+ def : Builtin<_Name,
+ [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0])]>;
+ }
+}
+multiclass Bif1<string _Name, list<Type> _Signature, list<bit> _IsVector> {
+ def : Builtin<_Name, _Signature>;
+ foreach v = [2, 3, 4, 8, 16] in {
+ def : Builtin<_Name,
+ [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
+ !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1])]>;
+ }
+}
+multiclass Bif2<string _Name, list<Type> _Signature, list<bit> _IsVector> {
+ def : Builtin<_Name, _Signature>;
+ foreach v = [2, 3, 4, 8, 16] in {
+ def : Builtin<_Name,
+ [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
+ !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
+ !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2])]>;
+ }
+}
+multiclass Bif3<string _Name, list<Type> _Signature, list<bit> _IsVector> {
+ def : Builtin<_Name, _Signature>;
+ foreach v = [2, 3, 4, 8, 16] in {
+ def : Builtin<_Name,
+ [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
+ !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
+ !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2]),
+ !if(_IsVector[3], VectorType<_Signature[3], v>, _Signature[3])]>;
+ }
+}
+//===----------------------------------------------------------------------===//
+// Definitions of OpenCL C types
+//===----------------------------------------------------------------------===//
+// OpenCL v1.2 s6.1.1: Built-in Scalar Data Types
+def bool_t : Type<"bool", QualType<"BoolTy">>;
+def char_t : Type<"char", QualType<"CharTy">>;
+def uchar_t : Type<"uchar", QualType<"UnsignedCharTy">>;
+def short_t : Type<"short", QualType<"ShortTy">>;
+def ushort_t : Type<"ushort", QualType<"UnsignedShortTy">>;
+def int_t : Type<"int", QualType<"IntTy">>;
+def uint_t : Type<"uint", QualType<"UnsignedIntTy">>;
+def long_t : Type<"long", QualType<"LongTy">>;
+def ulong_t : Type<"ulong", QualType<"UnsignedLongTy">>;
+def float_t : Type<"float", QualType<"FloatTy">>;
+def double_t : Type<"double", QualType<"DoubleTy">>;
+def half_t : Type<"half", QualType<"HalfTy">>;
+def size_t : Type<"size_t", QualType<"getSizeType()">>;
+def ptrdiff_t : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>;
+def intptr_t : Type<"intptr_t", QualType<"getIntPtrType()">>;
+def uintptr_t : Type<"uintptr_t", QualType<"getUIntPtrType()">>;
+def void_t : Type<"void", QualType<"VoidTy">>;
+
+// OpenCL v1.2 s6.1.2: Built-in Vector Data Types
+foreach v = [2, 3, 4, 8, 16] in {
+ def char#v#_t : VectorType<char_t, v>;
+ def uchar#v#_t : VectorType<uchar_t, v>;
+ def short#v#_t : VectorType<short_t, v>;
+ def ushort#v#_t : VectorType<ushort_t, v>;
+ def "int"#v#_t : VectorType<int_t, v>;
+ def uint#v#_t : VectorType<uint_t, v>;
+ def long#v#_t : VectorType<long_t, v>;
+ def ulong#v#_t : VectorType<ulong_t, v>;
+ def float#v#_t : VectorType<float_t, v>;
+ def double#v#_t : VectorType<double_t, v>;
+ def half#v#_t : VectorType<half_t, v>;
+}
+
+// OpenCL v1.2 s6.1.3: Other Built-in Data Types
+// These definitions with a "null" name are "abstract". They should not
+// be used in definitions of Builtin functions.
+def image2d_t : Type<"image2d_t", QualType<"null">>;
+def image3d_t : Type<"image3d_t", QualType<"null">>;
+def image2d_array_t : Type<"image2d_array_t", QualType<"null">>;
+def image1d_t : Type<"image1d_t", QualType<"null">>;
+def image1d_buffer_t : Type<"image1d_buffer_t", QualType<"null">>;
+def image1d_array_t : Type<"image1d_array_t", QualType<"null">>;
+// Unlike the few functions above, the following definitions can be used
+// in definitions of Builtin functions (they have a QualType with a name).
+foreach v = ["RO", "WO", "RW"] in {
+ def image2d_#v#_t : ImageType<image2d_t,
+ QualType<"OCLImage2d"#v#"Ty">,
+ v>;
+ def image3d_#v#_t : ImageType<image3d_t,
+ QualType<"OCLImage3d"#v#"Ty">,
+ v>;
+ def image2d_array#v#_t : ImageType<image2d_array_t,
+ QualType<"OCLImage2dArray"#v#"Ty">,
+ v>;
+ def image1d_#v#_t : ImageType<image1d_t,
+ QualType<"OCLImage1d"#v#"Ty">,
+ v>;
+ def image1d_buffer#v#_t : ImageType<image1d_buffer_t,
+ QualType<"OCLImage1dBuffer"#v#"Ty">,
+ v>;
+ def image1d_array#v#_t : ImageType<image1d_array_t,
+ QualType<"OCLImage1dArray"#v#"Ty">,
+ v>;
+}
+
+def sampler_t : Type<"sampler_t", QualType<"OCLSamplerTy">>;
+def event_t : Type<"event_t", QualType<"OCLEventTy">>;
+
+//===----------------------------------------------------------------------===//
+// Definitions of OpenCL builtin functions
+//===----------------------------------------------------------------------===//
+// OpenCL v1.2 s6.2.3: Explicit Conversions
+// Generate the convert_ builtins.
+foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
+ int_t, uint_t, long_t, ulong_t] in {
+ foreach IType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
+ int_t, uint_t, long_t, ulong_t] in {
+ foreach sat = ["", "_sat"] in {
+ foreach rte = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ def : Builtin<"convert_" # RType.Name # sat # rte, [RType, IType]>;
+ foreach v = [2, 3, 4, 8, 16] in {
+ def : Builtin<"convert_" # RType.Name # v # sat # rte,
+ [VectorType<RType, v>,
+ VectorType<IType, v>]>;
+ }
+ }
+ }
+ }
+}
+
+// OpenCL v1.2 s6.12.1: Work-Item Functions
+def get_work_dim : Builtin<"get_work_dim", [uint_t]>;
+foreach name = ["get_global_size", "get_global_id", "get_local_size",
+ "get_local_id", "get_num_groups", "get_group_id",
+ "get_global_offset"] in {
+ def : Builtin<name, [size_t, uint_t]>;
+}
+
+// OpenCL v1.2 s6.12.2: Math Functions
+foreach name = ["acos", "acosh", "acospi",
+ "asin", "asinh", "asinpi",
+ "atan", "atanh", "atanpi"] in {
+ foreach type = [float_t, double_t, half_t] in {
+ defm : Bif1<name, [type, type], [1, 1]>;
+ }
+}
+
+foreach name = ["atan2", "atan2pi"] in {
+ foreach type = [float_t, double_t, half_t] in {
+ defm : Bif2<name, [type, type, type], [1, 1, 1]>;
+ }
+}
+
+foreach name = ["fmax", "fmin"] in {
+ foreach type = [float_t, double_t, half_t] in {
+ defm : Bif2<name, [type, type, type], [1, 1, 1]>;
+ defm : Bif2<name, [type, type, type], [1, 1, 0]>;
+ }
+}
+
+// OpenCL v1.2 s6.12.14: Built-in Image Read Functions
+def read_imagef : Builtin<"read_imagef",
+ [float4_t, image2d_RO_t, VectorType<int_t, 2>]>;
+def write_imagef : Builtin<"write_imagef",
+ [void_t,
+ image2d_WO_t,
+ VectorType<int_t, 2>,
+ VectorType<float_t, 4>]>;
+
+
+// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
+let Version = CL20 in {
+ let Extension = "cl_khr_subgroups" in {
+ def get_sub_group_size : Builtin<"get_sub_group_size", [uint_t]>;
+ def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [uint_t]>;
+ def get_num_sub_groups : Builtin<"get_num_sub_groups", [uint_t]>;
+ }
+}
diff --git a/lib/Sema/ParsedAttr.cpp b/lib/Sema/ParsedAttr.cpp
index 59e5aab677a9..5c04443460bc 100644
--- a/lib/Sema/ParsedAttr.cpp
+++ b/lib/Sema/ParsedAttr.cpp
@@ -1,9 +1,8 @@
//======- ParsedAttr.cpp --------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index eae5a328bfa2..51b0b24e57b7 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -1,9 +1,8 @@
//===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -167,7 +166,9 @@ void Scope::dumpImpl(raw_ostream &OS) const {
{SEHExceptScope, "SEHExceptScope"},
{SEHFilterScope, "SEHFilterScope"},
{CompoundStmtScope, "CompoundStmtScope"},
- {ClassInheritanceScope, "ClassInheritanceScope"}};
+ {ClassInheritanceScope, "ClassInheritanceScope"},
+ {CatchScope, "CatchScope"},
+ };
for (auto Info : FlagInfo) {
if (Flags & Info.first) {
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index bd8db6f4ed91..b2a26af9b4a5 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -1,9 +1,8 @@
//===--- ScopeInfo.cpp - Information about a semantic context -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -113,21 +112,6 @@ FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
return BaseInfoTy(D, IsExact);
}
-bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
- RecordDecl *RD = nullptr;
- if (auto *LSI = dyn_cast<LambdaScopeInfo>(this))
- RD = LSI->Lambda;
- else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(this))
- RD = CRSI->TheRecordDecl;
-
- if (RD)
- for (auto *FD : RD->fields()) {
- if (FD->hasCapturedVLAType() && FD->getCapturedVLAType() == VAT)
- return true;
- }
- return false;
-}
-
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
const ObjCPropertyRefExpr *PropE)
: Base(nullptr, true), Property(getBestPropertyDecl(PropE)) {
@@ -232,20 +216,33 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
ThisUse->markSafe();
}
-void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD,
- Expr *&E) const {
- assert(Idx < getNumPotentialVariableCaptures() &&
- "Index of potential capture must be within 0 to less than the "
- "number of captures!");
- E = PotentiallyCapturingExprs[Idx];
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
- else if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
- VD = dyn_cast<VarDecl>(ME->getMemberDecl());
- else
- llvm_unreachable("Only DeclRefExprs or MemberExprs should be added for "
- "potential captures");
- assert(VD);
+bool Capture::isInitCapture() const {
+ // Note that a nested capture of an init-capture is not itself an
+ // init-capture.
+ return !isNested() && isVariableCapture() && getVariable()->isInitCapture();
+}
+
+bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
+ for (auto &Cap : Captures)
+ if (Cap.isVLATypeCapture() && Cap.getCapturedVLAType() == VAT)
+ return true;
+ return false;
+}
+
+void LambdaScopeInfo::visitPotentialCaptures(
+ llvm::function_ref<void(VarDecl *, Expr *)> Callback) const {
+ for (Expr *E : PotentiallyCapturingExprs) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ Callback(cast<VarDecl>(DRE->getFoundDecl()), E);
+ } else if (auto *ME = dyn_cast<MemberExpr>(E)) {
+ Callback(cast<VarDecl>(ME->getMemberDecl()), E);
+ } else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
+ for (VarDecl *VD : *FP)
+ Callback(VD, E);
+ } else {
+ llvm_unreachable("unexpected expression in potential captures list");
+ }
+ }
}
FunctionScopeInfo::~FunctionScopeInfo() { }
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 9fa39968625a..11fed28b52db 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -1,9 +1,8 @@
//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -40,6 +39,8 @@
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/TimeProfiler.h"
+
using namespace clang;
using namespace sema;
@@ -93,6 +94,12 @@ public:
SourceManager &SM = S->getSourceManager();
SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc));
if (IncludeLoc.isValid()) {
+ if (llvm::timeTraceProfilerEnabled()) {
+ const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc));
+ llvm::timeTraceProfilerBegin(
+ "Source", FE != nullptr ? FE->getName() : StringRef("<unknown>"));
+ }
+
IncludeStack.push_back(IncludeLoc);
S->DiagnoseNonDefaultPragmaPack(
Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc);
@@ -100,10 +107,14 @@ public:
break;
}
case ExitFile:
- if (!IncludeStack.empty())
+ if (!IncludeStack.empty()) {
+ if (llvm::timeTraceProfilerEnabled())
+ llvm::timeTraceProfilerEnd();
+
S->DiagnoseNonDefaultPragmaPack(
Sema::PragmaPackDiagnoseKind::ChangedStateAtExit,
IncludeStack.pop_back_val());
+ }
break;
default:
break;
@@ -147,6 +158,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
+ isConstantEvaluatedOverride = false;
LoadedExternalKnownNamespaces = false;
for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)
@@ -165,8 +177,6 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{},
nullptr, ExpressionEvaluationContextRecord::EK_Other);
- PreallocatedFunctionScope.reset(new FunctionScopeInfo(Diags));
-
// Initialization of data sharing attributes stack for OpenMP
InitDataSharingAttributesStack();
@@ -256,11 +266,12 @@ void Sema::Initialize() {
// Initialize predefined OpenCL types and supported extensions and (optional)
// core features.
if (getLangOpts().OpenCL) {
- getOpenCLOptions().addSupport(Context.getTargetInfo().getSupportedOpenCLOpts());
- getOpenCLOptions().enableSupportedCore(getLangOpts().OpenCLVersion);
+ getOpenCLOptions().addSupport(
+ Context.getTargetInfo().getSupportedOpenCLOpts());
+ getOpenCLOptions().enableSupportedCore(getLangOpts());
addImplicitTypedef("sampler_t", Context.OCLSamplerTy);
addImplicitTypedef("event_t", Context.OCLEventTy);
- if (getLangOpts().OpenCLVersion >= 200) {
+ if (getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) {
addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
addImplicitTypedef("queue_t", Context.OCLQueueTy);
addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
@@ -342,8 +353,7 @@ Sema::~Sema() {
// Kill all the active scopes.
for (sema::FunctionScopeInfo *FSI : FunctionScopes)
- if (FSI != PreallocatedFunctionScope.get())
- delete FSI;
+ delete FSI;
// Tell the SemaConsumer to forget about us; we're going out of scope.
if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer))
@@ -481,6 +491,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
default:
llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast "
"kind");
+ case CK_Dependent:
case CK_LValueToRValue:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
@@ -489,7 +500,8 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
break;
}
}
- assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue");
+ assert((VK == VK_RValue || Kind == CK_Dependent || !E->isRValue()) &&
+ "can't cast rvalue to lvalue");
#endif
diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getBeginLoc());
@@ -578,7 +590,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
// warn even if the variable isn't odr-used. (isReferenced doesn't
// precisely reflect that, but it's a decent approximation.)
if (VD->isReferenced() &&
- VD->isUsableInConstantExpressions(SemaRef->Context))
+ VD->mightBeUsableInConstantExpressions(SemaRef->Context))
return true;
if (VarTemplateDecl *Template = VD->getDescribedVarTemplate())
@@ -837,41 +849,21 @@ void Sema::ActOnStartOfTranslationUnit() {
if (getLangOpts().ModulesTS &&
(getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface ||
getLangOpts().getCompilingModule() == LangOptions::CMK_None)) {
+ // We start in an implied global module fragment.
SourceLocation StartOfTU =
SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
-
- // We start in the global module; all those declarations are implicitly
- // module-private (though they do not have module linkage).
- auto &Map = PP.getHeaderSearchInfo().getModuleMap();
- auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU);
- assert(GlobalModule && "module creation should not fail");
-
- // Enter the scope of the global module.
- ModuleScopes.push_back({});
- ModuleScopes.back().Module = GlobalModule;
- VisibleModules.setVisible(GlobalModule, StartOfTU);
-
- // All declarations created from now on are owned by the global module.
- auto *TU = Context.getTranslationUnitDecl();
- TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
- TU->setLocalOwningModule(GlobalModule);
+ ActOnGlobalModuleFragmentDecl(StartOfTU);
+ ModuleScopes.back().ImplicitGlobalModuleFragment = true;
}
}
-/// ActOnEndOfTranslationUnit - This is called at the very end of the
-/// translation unit when EOF is reached and all but the top-level scope is
-/// popped.
-void Sema::ActOnEndOfTranslationUnit() {
- assert(DelayedDiagnostics.getCurrentPool() == nullptr
- && "reached end of translation unit with a pool attached?");
-
- // If code completion is enabled, don't perform any end-of-translation-unit
- // work.
- if (PP.isCodeCompletionEnabled())
+void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
+ // No explicit actions are required at the end of the global module fragment.
+ if (Kind == TUFragmentKind::Global)
return;
// Transfer late parsed template instantiations over to the pending template
- // instantiation list. During normal compliation, the late template parser
+ // instantiation list. During normal compilation, the late template parser
// will be installed and instantiating these templates will succeed.
//
// If we are building a TU prefix for serialization, it is also safe to
@@ -884,46 +876,79 @@ void Sema::ActOnEndOfTranslationUnit() {
LateParsedInstantiations.end());
LateParsedInstantiations.clear();
+ // If DefinedUsedVTables ends up marking any virtual member functions it
+ // might lead to more pending template instantiations, which we then need
+ // to instantiate.
+ DefineUsedVTables();
+
+ // C++: Perform implicit template instantiations.
+ //
+ // FIXME: When we perform these implicit instantiations, we do not
+ // carefully keep track of the point of instantiation (C++ [temp.point]).
+ // This means that name lookup that occurs within the template
+ // instantiation will always happen at the end of the translation unit,
+ // so it will find some names that are not required to be found. This is
+ // valid, but we could do better by diagnosing if an instantiation uses a
+ // name that was not visible at its first point of instantiation.
+ if (ExternalSource) {
+ // Load pending instantiations from the external source.
+ SmallVector<PendingImplicitInstantiation, 4> Pending;
+ ExternalSource->ReadPendingInstantiations(Pending);
+ for (auto PII : Pending)
+ if (auto Func = dyn_cast<FunctionDecl>(PII.first))
+ Func->setInstantiationIsPending(true);
+ PendingInstantiations.insert(PendingInstantiations.begin(),
+ Pending.begin(), Pending.end());
+ }
+
+ {
+ llvm::TimeTraceScope TimeScope("PerformPendingInstantiations",
+ StringRef(""));
+ PerformPendingInstantiations();
+ }
+
+ assert(LateParsedInstantiations.empty() &&
+ "end of TU template instantiation should not create more "
+ "late-parsed templates");
+}
+
+/// ActOnEndOfTranslationUnit - This is called at the very end of the
+/// translation unit when EOF is reached and all but the top-level scope is
+/// popped.
+void Sema::ActOnEndOfTranslationUnit() {
+ assert(DelayedDiagnostics.getCurrentPool() == nullptr
+ && "reached end of translation unit with a pool attached?");
+
+ // If code completion is enabled, don't perform any end-of-translation-unit
+ // work.
+ if (PP.isCodeCompletionEnabled())
+ return;
+
// Complete translation units and modules define vtables and perform implicit
// instantiations. PCH files do not.
if (TUKind != TU_Prefix) {
DiagnoseUseOfUnimplementedSelectors();
- // If DefinedUsedVTables ends up marking any virtual member functions it
- // might lead to more pending template instantiations, which we then need
- // to instantiate.
- DefineUsedVTables();
-
- // C++: Perform implicit template instantiations.
- //
- // FIXME: When we perform these implicit instantiations, we do not
- // carefully keep track of the point of instantiation (C++ [temp.point]).
- // This means that name lookup that occurs within the template
- // instantiation will always happen at the end of the translation unit,
- // so it will find some names that are not required to be found. This is
- // valid, but we could do better by diagnosing if an instantiation uses a
- // name that was not visible at its first point of instantiation.
- if (ExternalSource) {
- // Load pending instantiations from the external source.
- SmallVector<PendingImplicitInstantiation, 4> Pending;
- ExternalSource->ReadPendingInstantiations(Pending);
- for (auto PII : Pending)
- if (auto Func = dyn_cast<FunctionDecl>(PII.first))
- Func->setInstantiationIsPending(true);
- PendingInstantiations.insert(PendingInstantiations.begin(),
- Pending.begin(), Pending.end());
- }
-
- PerformPendingInstantiations();
-
- assert(LateParsedInstantiations.empty() &&
- "end of TU template instantiation should not create more "
- "late-parsed templates");
+ ActOnEndOfTranslationUnitFragment(
+ !ModuleScopes.empty() && ModuleScopes.back().Module->Kind ==
+ Module::PrivateModuleFragment
+ ? TUFragmentKind::Private
+ : TUFragmentKind::Normal);
if (LateTemplateParserCleanup)
LateTemplateParserCleanup(OpaqueParser);
CheckDelayedMemberExceptionSpecs();
+ } else {
+ // If we are building a TU prefix for serialization, it is safe to transfer
+ // these over, even though they are not parsed. The end of the TU should be
+ // outside of any eager template instantiation scope, so when this AST is
+ // deserialized, these templates will not be parsed until the end of the
+ // combined TU.
+ PendingInstantiations.insert(PendingInstantiations.end(),
+ LateParsedInstantiations.begin(),
+ LateParsedInstantiations.end());
+ LateParsedInstantiations.clear();
}
DiagnoseUnterminatedPragmaPack();
@@ -933,7 +958,6 @@ void Sema::ActOnEndOfTranslationUnit() {
// incompatible declarations.
assert(DelayedOverridingExceptionSpecChecks.empty());
assert(DelayedEquivalentExceptionSpecChecks.empty());
- assert(DelayedDefaultedMemberExceptionSpecs.empty());
// All dllexport classes should have been processed already.
assert(DelayedDllExportClasses.empty());
@@ -981,13 +1005,24 @@ void Sema::ActOnEndOfTranslationUnit() {
checkUndefinedButUsed(*this);
}
+ // A global-module-fragment is only permitted within a module unit.
+ bool DiagnosedMissingModuleDeclaration = false;
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment &&
+ !ModuleScopes.back().ImplicitGlobalModuleFragment) {
+ Diag(ModuleScopes.back().BeginLoc,
+ diag::err_module_declaration_missing_after_global_module_introducer);
+ DiagnosedMissingModuleDeclaration = true;
+ }
+
if (TUKind == TU_Module) {
// If we are building a module interface unit, we need to have seen the
// module declaration by now.
if (getLangOpts().getCompilingModule() ==
LangOptions::CMK_ModuleInterface &&
(ModuleScopes.empty() ||
- ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) {
+ !ModuleScopes.back().Module->isModulePurview()) &&
+ !DiagnosedMissingModuleDeclaration) {
// FIXME: Make a better guess as to where to put the module declaration.
Diag(getSourceManager().getLocForStartOfFile(
getSourceManager().getMainFileID()),
@@ -1325,6 +1360,190 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
return Builder;
}
+// Print notes showing how we can reach FD starting from an a priori
+// known-callable function.
+static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
+ auto FnIt = S.DeviceKnownEmittedFns.find(FD);
+ while (FnIt != S.DeviceKnownEmittedFns.end()) {
+ DiagnosticBuilder Builder(
+ S.Diags.Report(FnIt->second.Loc, diag::note_called_by));
+ Builder << FnIt->second.FD;
+ Builder.setForceEmit();
+
+ FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD);
+ }
+}
+
+// Emit any deferred diagnostics for FD and erase them from the map in which
+// they're stored.
+static void emitDeferredDiags(Sema &S, FunctionDecl *FD) {
+ auto It = S.DeviceDeferredDiags.find(FD);
+ if (It == S.DeviceDeferredDiags.end())
+ return;
+ bool HasWarningOrError = false;
+ for (PartialDiagnosticAt &PDAt : It->second) {
+ const SourceLocation &Loc = PDAt.first;
+ const PartialDiagnostic &PD = PDAt.second;
+ HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel(
+ PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning;
+ DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID()));
+ Builder.setForceEmit();
+ PD.Emit(Builder);
+ }
+ S.DeviceDeferredDiags.erase(It);
+
+ // FIXME: Should this be called after every warning/error emitted in the loop
+ // above, instead of just once per function? That would be consistent with
+ // how we handle immediate errors, but it also seems like a bit much.
+ if (HasWarningOrError)
+ emitCallStackNotes(S, FD);
+}
+
+// In CUDA, there are some constructs which may appear in semantically-valid
+// code, but trigger errors if we ever generate code for the function in which
+// they appear. Essentially every construct you're not allowed to use on the
+// device falls into this category, because you are allowed to use these
+// constructs in a __host__ __device__ function, but only if that function is
+// never codegen'ed on the device.
+//
+// To handle semantic checking for these constructs, we keep track of the set of
+// functions we know will be emitted, either because we could tell a priori that
+// they would be emitted, or because they were transitively called by a
+// known-emitted function.
+//
+// We also keep a partial call graph of which not-known-emitted functions call
+// which other not-known-emitted functions.
+//
+// When we see something which is illegal if the current function is emitted
+// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or
+// CheckCUDACall), we first check if the current function is known-emitted. If
+// so, we immediately output the diagnostic.
+//
+// Otherwise, we "defer" the diagnostic. It sits in Sema::DeviceDeferredDiags
+// until we discover that the function is known-emitted, at which point we take
+// it out of this map and emit the diagnostic.
+
+Sema::DeviceDiagBuilder::DeviceDiagBuilder(Kind K, SourceLocation Loc,
+ unsigned DiagID, FunctionDecl *Fn,
+ Sema &S)
+ : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn),
+ ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) {
+ switch (K) {
+ case K_Nop:
+ break;
+ case K_Immediate:
+ case K_ImmediateWithCallStack:
+ ImmediateDiag.emplace(S.Diag(Loc, DiagID));
+ break;
+ case K_Deferred:
+ assert(Fn && "Must have a function to attach the deferred diag to.");
+ auto &Diags = S.DeviceDeferredDiags[Fn];
+ PartialDiagId.emplace(Diags.size());
+ Diags.emplace_back(Loc, S.PDiag(DiagID));
+ break;
+ }
+}
+
+Sema::DeviceDiagBuilder::DeviceDiagBuilder(DeviceDiagBuilder &&D)
+ : S(D.S), Loc(D.Loc), DiagID(D.DiagID), Fn(D.Fn),
+ ShowCallStack(D.ShowCallStack), ImmediateDiag(D.ImmediateDiag),
+ PartialDiagId(D.PartialDiagId) {
+ // Clean the previous diagnostics.
+ D.ShowCallStack = false;
+ D.ImmediateDiag.reset();
+ D.PartialDiagId.reset();
+}
+
+Sema::DeviceDiagBuilder::~DeviceDiagBuilder() {
+ if (ImmediateDiag) {
+ // Emit our diagnostic and, if it was a warning or error, output a callstack
+ // if Fn isn't a priori known-emitted.
+ bool IsWarningOrError = S.getDiagnostics().getDiagnosticLevel(
+ DiagID, Loc) >= DiagnosticsEngine::Warning;
+ ImmediateDiag.reset(); // Emit the immediate diag.
+ if (IsWarningOrError && ShowCallStack)
+ emitCallStackNotes(S, Fn);
+ } else {
+ assert((!PartialDiagId || ShowCallStack) &&
+ "Must always show call stack for deferred diags.");
+ }
+}
+
+// Indicate that this function (and thus everything it transtively calls) will
+// be codegen'ed, and emit any deferred diagnostics on this function and its
+// (transitive) callees.
+void Sema::markKnownEmitted(
+ Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee,
+ SourceLocation OrigLoc,
+ const llvm::function_ref<bool(Sema &, FunctionDecl *)> IsKnownEmitted) {
+ // Nothing to do if we already know that FD is emitted.
+ if (IsKnownEmitted(S, OrigCallee)) {
+ assert(!S.DeviceCallGraph.count(OrigCallee));
+ return;
+ }
+
+ // We've just discovered that OrigCallee is known-emitted. Walk our call
+ // graph to see what else we can now discover also must be emitted.
+
+ struct CallInfo {
+ FunctionDecl *Caller;
+ FunctionDecl *Callee;
+ SourceLocation Loc;
+ };
+ llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}};
+ llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen;
+ Seen.insert(OrigCallee);
+ while (!Worklist.empty()) {
+ CallInfo C = Worklist.pop_back_val();
+ assert(!IsKnownEmitted(S, C.Callee) &&
+ "Worklist should not contain known-emitted functions.");
+ S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc};
+ emitDeferredDiags(S, C.Callee);
+
+ // If this is a template instantiation, explore its callgraph as well:
+ // Non-dependent calls are part of the template's callgraph, while dependent
+ // calls are part of to the instantiation's call graph.
+ if (auto *Templ = C.Callee->getPrimaryTemplate()) {
+ FunctionDecl *TemplFD = Templ->getAsFunction();
+ if (!Seen.count(TemplFD) && !S.DeviceKnownEmittedFns.count(TemplFD)) {
+ Seen.insert(TemplFD);
+ Worklist.push_back(
+ {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc});
+ }
+ }
+
+ // Add all functions called by Callee to our worklist.
+ auto CGIt = S.DeviceCallGraph.find(C.Callee);
+ if (CGIt == S.DeviceCallGraph.end())
+ continue;
+
+ for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc :
+ CGIt->second) {
+ FunctionDecl *NewCallee = FDLoc.first;
+ SourceLocation CallLoc = FDLoc.second;
+ if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee))
+ continue;
+ Seen.insert(NewCallee);
+ Worklist.push_back(
+ {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc});
+ }
+
+ // C.Callee is now known-emitted, so we no longer need to maintain its list
+ // of callees in DeviceCallGraph.
+ S.DeviceCallGraph.erase(CGIt);
+ }
+}
+
+Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
+ if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+ return diagIfOpenMPDeviceCode(Loc, DiagID);
+ if (getLangOpts().CUDA)
+ return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
+ : CUDADiagIfHostCode(Loc, DiagID);
+ return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID,
+ getCurFunctionDecl(), *this);
+}
+
/// Looks through the macro-expansion chain for the given
/// location, looking for a macro expansion with the given name.
/// If one is found, returns true and sets the location to that
@@ -1377,10 +1596,10 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) {
/// Enter a new function scope
void Sema::PushFunctionScope() {
- if (FunctionScopes.empty()) {
- // Use PreallocatedFunctionScope to avoid allocating memory when possible.
- PreallocatedFunctionScope->Clear();
- FunctionScopes.push_back(PreallocatedFunctionScope.get());
+ if (FunctionScopes.empty() && CachedFunctionScope) {
+ // Use CachedFunctionScope to avoid allocating memory when possible.
+ CachedFunctionScope->Clear();
+ FunctionScopes.push_back(CachedFunctionScope.release());
} else {
FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
}
@@ -1409,7 +1628,7 @@ void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
}
// Check that the type of the VarDecl has an accessible copy constructor and
-// resolve its destructor's exception spefication.
+// resolve its destructor's exception specification.
static void checkEscapingByref(VarDecl *VD, Sema &S) {
QualType T = VD->getType();
EnterExpressionEvaluationContext scope(
@@ -1426,7 +1645,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) {
S.Context.setBlockVarCopyInit(VD, Init, S.canThrow(Init));
}
- // The destructor's exception spefication is needed when IRGen generates
+ // The destructor's exception specification is needed when IRGen generates
// block copy/destroy functions. Resolve it here.
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
if (CXXDestructorDecl *DD = RD->getDestructor()) {
@@ -1439,12 +1658,24 @@ static void markEscapingByrefs(const FunctionScopeInfo &FSI, Sema &S) {
// Set the EscapingByref flag of __block variables captured by
// escaping blocks.
for (const BlockDecl *BD : FSI.Blocks) {
- if (BD->doesNotEscape())
- continue;
for (const BlockDecl::Capture &BC : BD->captures()) {
VarDecl *VD = BC.getVariable();
- if (VD->hasAttr<BlocksAttr>())
+ if (VD->hasAttr<BlocksAttr>()) {
+ // Nothing to do if this is a __block variable captured by a
+ // non-escaping block.
+ if (BD->doesNotEscape())
+ continue;
VD->setEscapingByref();
+ }
+ // Check whether the captured variable is or contains an object of
+ // non-trivial C union type.
+ QualType CapType = BC.getVariable()->getType();
+ if (CapType.hasNonTrivialToPrimitiveDestructCUnion() ||
+ CapType.hasNonTrivialToPrimitiveCopyCUnion())
+ S.checkNonTrivialCUnion(BC.getVariable()->getType(),
+ BD->getCaretLocation(),
+ Sema::NTCUC_BlockCapture,
+ Sema::NTCUK_Destruct|Sema::NTCUK_Copy);
}
}
@@ -1461,30 +1692,42 @@ static void markEscapingByrefs(const FunctionScopeInfo &FSI, Sema &S) {
}
}
-void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
- const Decl *D, const BlockExpr *blkExpr) {
+/// Pop a function (or block or lambda or captured region) scope from the stack.
+///
+/// \param WP The warning policy to use for CFG-based warnings, or null if such
+/// warnings should not be produced.
+/// \param D The declaration corresponding to this function scope, if producing
+/// CFG-based warnings.
+/// \param BlockType The type of the block expression, if D is a BlockDecl.
+Sema::PoppedFunctionScopePtr
+Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
+ const Decl *D, QualType BlockType) {
assert(!FunctionScopes.empty() && "mismatched push/pop!");
- // This function shouldn't be called after popping the current function scope.
- // markEscapingByrefs calls PerformMoveOrCopyInitialization, which can call
- // PushFunctionScope, which can cause clearing out PreallocatedFunctionScope
- // when FunctionScopes is empty.
markEscapingByrefs(*FunctionScopes.back(), *this);
- FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
+ PoppedFunctionScopePtr Scope(FunctionScopes.pop_back_val(),
+ PoppedFunctionScopeDeleter(this));
if (LangOpts.OpenMP)
- popOpenMPFunctionRegion(Scope);
+ popOpenMPFunctionRegion(Scope.get());
// Issue any analysis-based warnings.
if (WP && D)
- AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
+ AnalysisWarnings.IssueWarnings(*WP, Scope.get(), D, BlockType);
else
for (const auto &PUD : Scope->PossiblyUnreachableDiags)
Diag(PUD.Loc, PUD.PD);
- // Delete the scope unless its our preallocated scope.
- if (Scope != PreallocatedFunctionScope.get())
+ return Scope;
+}
+
+void Sema::PoppedFunctionScopeDeleter::
+operator()(sema::FunctionScopeInfo *Scope) const {
+ // Stash the function scope for later reuse if it's for a normal function.
+ if (Scope->isPlainFunction() && !Self->CachedFunctionScope)
+ Self->CachedFunctionScope.reset(Scope);
+ else
delete Scope;
}
@@ -1573,7 +1816,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
if (LambdaScopeInfo *LSI = getCurLambda()) {
- return (LSI->AutoTemplateParams.size() ||
+ return (LSI->TemplateParams.size() ||
LSI->GLTemplateParameterList) ? LSI : nullptr;
}
return nullptr;
@@ -1841,7 +2084,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// FIXME: Try this before emitting the fixit, and suppress diagnostics
// while doing so.
- E = ActOnCallExpr(nullptr, E.get(), Range.getEnd(), None,
+ E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), None,
Range.getEnd().getLocWithOffset(1));
return true;
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 69084589efea..b6fbbbff91f5 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -1,9 +1,8 @@
//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -127,8 +126,7 @@ struct EffectiveContext {
bool includesClass(const CXXRecordDecl *R) const {
R = R->getCanonicalDecl();
- return std::find(Records.begin(), Records.end(), R)
- != Records.end();
+ return llvm::find(Records, R) != Records.end();
}
/// Retrieves the innermost "useful" context. Can be null if we're
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 2bc1b769f77a..8e9318847373 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -1,9 +1,8 @@
//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -404,9 +403,15 @@ void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
if (Action & PSK_Pop && Stack->Stack.empty())
Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName
<< "stack empty";
- if (SegmentName &&
- !checkSectionName(SegmentName->getBeginLoc(), SegmentName->getString()))
- return;
+ if (SegmentName) {
+ if (!checkSectionName(SegmentName->getBeginLoc(), SegmentName->getString()))
+ return;
+
+ if (SegmentName->getString() == ".drectve" &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft())
+ Diag(PragmaLocation, diag::warn_attribute_section_drectve) << PragmaName;
+ }
+
Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
}
@@ -523,6 +528,7 @@ attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) {
void Sema::ActOnPragmaAttributeAttribute(
ParsedAttr &Attribute, SourceLocation PragmaLoc,
attr::ParsedSubjectMatchRuleSet Rules) {
+ Attribute.setIsPragmaClangAttribute();
SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
// Gather the subject match rules that are supported by the attribute.
SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
@@ -680,6 +686,8 @@ void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
for (auto &Entry : Group.Entries) {
ParsedAttr *Attribute = Entry.Attribute;
assert(Attribute && "Expected an attribute");
+ assert(Attribute->isPragmaClangAttribute() &&
+ "expected #pragma clang attribute");
// Ensure that the attribute can be applied to the given declaration.
bool Applies = false;
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index ffc728898584..203c09c57112 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -1,9 +1,8 @@
//===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -14,6 +13,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/Cuda.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
@@ -42,16 +42,15 @@ ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
SourceLocation GGGLoc) {
FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
if (!ConfigDecl)
- return ExprError(
- Diag(LLLLoc, diag::err_undeclared_var_use)
- << (getLangOpts().HIP ? "hipConfigureCall" : "cudaConfigureCall"));
+ return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
+ << getCudaConfigureFuncName());
QualType ConfigQTy = ConfigDecl->getType();
DeclRefExpr *ConfigDR = new (Context)
DeclRefExpr(Context, ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
MarkFunctionReferenced(LLLLoc, ConfigDecl);
- return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
+ return BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
/*IsExecConfig=*/true);
}
@@ -587,78 +586,6 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
}
-// In CUDA, there are some constructs which may appear in semantically-valid
-// code, but trigger errors if we ever generate code for the function in which
-// they appear. Essentially every construct you're not allowed to use on the
-// device falls into this category, because you are allowed to use these
-// constructs in a __host__ __device__ function, but only if that function is
-// never codegen'ed on the device.
-//
-// To handle semantic checking for these constructs, we keep track of the set of
-// functions we know will be emitted, either because we could tell a priori that
-// they would be emitted, or because they were transitively called by a
-// known-emitted function.
-//
-// We also keep a partial call graph of which not-known-emitted functions call
-// which other not-known-emitted functions.
-//
-// When we see something which is illegal if the current function is emitted
-// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or
-// CheckCUDACall), we first check if the current function is known-emitted. If
-// so, we immediately output the diagnostic.
-//
-// Otherwise, we "defer" the diagnostic. It sits in Sema::CUDADeferredDiags
-// until we discover that the function is known-emitted, at which point we take
-// it out of this map and emit the diagnostic.
-
-Sema::CUDADiagBuilder::CUDADiagBuilder(Kind K, SourceLocation Loc,
- unsigned DiagID, FunctionDecl *Fn,
- Sema &S)
- : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn),
- ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) {
- switch (K) {
- case K_Nop:
- break;
- case K_Immediate:
- case K_ImmediateWithCallStack:
- ImmediateDiag.emplace(S.Diag(Loc, DiagID));
- break;
- case K_Deferred:
- assert(Fn && "Must have a function to attach the deferred diag to.");
- PartialDiag.emplace(S.PDiag(DiagID));
- break;
- }
-}
-
-// Print notes showing how we can reach FD starting from an a priori
-// known-callable function.
-static void EmitCallStackNotes(Sema &S, FunctionDecl *FD) {
- auto FnIt = S.CUDAKnownEmittedFns.find(FD);
- while (FnIt != S.CUDAKnownEmittedFns.end()) {
- DiagnosticBuilder Builder(
- S.Diags.Report(FnIt->second.Loc, diag::note_called_by));
- Builder << FnIt->second.FD;
- Builder.setForceEmit();
-
- FnIt = S.CUDAKnownEmittedFns.find(FnIt->second.FD);
- }
-}
-
-Sema::CUDADiagBuilder::~CUDADiagBuilder() {
- if (ImmediateDiag) {
- // Emit our diagnostic and, if it was a warning or error, output a callstack
- // if Fn isn't a priori known-emitted.
- bool IsWarningOrError = S.getDiagnostics().getDiagnosticLevel(
- DiagID, Loc) >= DiagnosticsEngine::Warning;
- ImmediateDiag.reset(); // Emit the immediate diag.
- if (IsWarningOrError && ShowCallStack)
- EmitCallStackNotes(S, Fn);
- } else if (PartialDiag) {
- assert(ShowCallStack && "Must always show call stack for deferred diags.");
- S.CUDADeferredDiags[Fn].push_back({Loc, std::move(*PartialDiag)});
- }
-}
-
// Do we know that we will eventually codegen the given function?
static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
// Templates are emitted when they're instantiated.
@@ -690,152 +617,69 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
// Otherwise, the function is known-emitted if it's in our set of
// known-emitted functions.
- return S.CUDAKnownEmittedFns.count(FD) > 0;
+ return S.DeviceKnownEmittedFns.count(FD) > 0;
}
-Sema::CUDADiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
- unsigned DiagID) {
+Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
+ unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
- CUDADiagBuilder::Kind DiagKind = [&] {
+ DeviceDiagBuilder::Kind DiagKind = [this] {
switch (CurrentCUDATarget()) {
case CFT_Global:
case CFT_Device:
- return CUDADiagBuilder::K_Immediate;
+ return DeviceDiagBuilder::K_Immediate;
case CFT_HostDevice:
// An HD function counts as host code if we're compiling for host, and
// device code if we're compiling for device. Defer any errors in device
// mode until the function is known-emitted.
if (getLangOpts().CUDAIsDevice) {
return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext))
- ? CUDADiagBuilder::K_ImmediateWithCallStack
- : CUDADiagBuilder::K_Deferred;
+ ? DeviceDiagBuilder::K_ImmediateWithCallStack
+ : DeviceDiagBuilder::K_Deferred;
}
- return CUDADiagBuilder::K_Nop;
+ return DeviceDiagBuilder::K_Nop;
default:
- return CUDADiagBuilder::K_Nop;
+ return DeviceDiagBuilder::K_Nop;
}
}();
- return CUDADiagBuilder(DiagKind, Loc, DiagID,
- dyn_cast<FunctionDecl>(CurContext), *this);
+ return DeviceDiagBuilder(DiagKind, Loc, DiagID,
+ dyn_cast<FunctionDecl>(CurContext), *this);
}
-Sema::CUDADiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
- unsigned DiagID) {
+Sema::DeviceDiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
+ unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
- CUDADiagBuilder::Kind DiagKind = [&] {
+ DeviceDiagBuilder::Kind DiagKind = [this] {
switch (CurrentCUDATarget()) {
case CFT_Host:
- return CUDADiagBuilder::K_Immediate;
+ return DeviceDiagBuilder::K_Immediate;
case CFT_HostDevice:
// An HD function counts as host code if we're compiling for host, and
// device code if we're compiling for device. Defer any errors in device
// mode until the function is known-emitted.
if (getLangOpts().CUDAIsDevice)
- return CUDADiagBuilder::K_Nop;
+ return DeviceDiagBuilder::K_Nop;
return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext))
- ? CUDADiagBuilder::K_ImmediateWithCallStack
- : CUDADiagBuilder::K_Deferred;
+ ? DeviceDiagBuilder::K_ImmediateWithCallStack
+ : DeviceDiagBuilder::K_Deferred;
default:
- return CUDADiagBuilder::K_Nop;
+ return DeviceDiagBuilder::K_Nop;
}
}();
- return CUDADiagBuilder(DiagKind, Loc, DiagID,
- dyn_cast<FunctionDecl>(CurContext), *this);
-}
-
-// Emit any deferred diagnostics for FD and erase them from the map in which
-// they're stored.
-static void EmitDeferredDiags(Sema &S, FunctionDecl *FD) {
- auto It = S.CUDADeferredDiags.find(FD);
- if (It == S.CUDADeferredDiags.end())
- return;
- bool HasWarningOrError = false;
- for (PartialDiagnosticAt &PDAt : It->second) {
- const SourceLocation &Loc = PDAt.first;
- const PartialDiagnostic &PD = PDAt.second;
- HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel(
- PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning;
- DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID()));
- Builder.setForceEmit();
- PD.Emit(Builder);
- }
- S.CUDADeferredDiags.erase(It);
-
- // FIXME: Should this be called after every warning/error emitted in the loop
- // above, instead of just once per function? That would be consistent with
- // how we handle immediate errors, but it also seems like a bit much.
- if (HasWarningOrError)
- EmitCallStackNotes(S, FD);
-}
-
-// Indicate that this function (and thus everything it transtively calls) will
-// be codegen'ed, and emit any deferred diagnostics on this function and its
-// (transitive) callees.
-static void MarkKnownEmitted(Sema &S, FunctionDecl *OrigCaller,
- FunctionDecl *OrigCallee, SourceLocation OrigLoc) {
- // Nothing to do if we already know that FD is emitted.
- if (IsKnownEmitted(S, OrigCallee)) {
- assert(!S.CUDACallGraph.count(OrigCallee));
- return;
- }
-
- // We've just discovered that OrigCallee is known-emitted. Walk our call
- // graph to see what else we can now discover also must be emitted.
-
- struct CallInfo {
- FunctionDecl *Caller;
- FunctionDecl *Callee;
- SourceLocation Loc;
- };
- llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}};
- llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen;
- Seen.insert(OrigCallee);
- while (!Worklist.empty()) {
- CallInfo C = Worklist.pop_back_val();
- assert(!IsKnownEmitted(S, C.Callee) &&
- "Worklist should not contain known-emitted functions.");
- S.CUDAKnownEmittedFns[C.Callee] = {C.Caller, C.Loc};
- EmitDeferredDiags(S, C.Callee);
-
- // If this is a template instantiation, explore its callgraph as well:
- // Non-dependent calls are part of the template's callgraph, while dependent
- // calls are part of to the instantiation's call graph.
- if (auto *Templ = C.Callee->getPrimaryTemplate()) {
- FunctionDecl *TemplFD = Templ->getAsFunction();
- if (!Seen.count(TemplFD) && !S.CUDAKnownEmittedFns.count(TemplFD)) {
- Seen.insert(TemplFD);
- Worklist.push_back(
- {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc});
- }
- }
-
- // Add all functions called by Callee to our worklist.
- auto CGIt = S.CUDACallGraph.find(C.Callee);
- if (CGIt == S.CUDACallGraph.end())
- continue;
-
- for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc :
- CGIt->second) {
- FunctionDecl *NewCallee = FDLoc.first;
- SourceLocation CallLoc = FDLoc.second;
- if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee))
- continue;
- Seen.insert(NewCallee);
- Worklist.push_back(
- {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc});
- }
-
- // C.Callee is now known-emitted, so we no longer need to maintain its list
- // of callees in CUDACallGraph.
- S.CUDACallGraph.erase(CGIt);
- }
+ return DeviceDiagBuilder(DiagKind, Loc, DiagID,
+ dyn_cast<FunctionDecl>(CurContext), *this);
}
bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
assert(Callee && "Callee may not be null.");
+
+ auto &ExprEvalCtx = ExprEvalContexts.back();
+ if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated())
+ return true;
+
// FIXME: Is bailing out early correct here? Should we instead assume that
// the caller is a global initializer?
FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext);
@@ -849,7 +693,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// Host-side references to a __global__ function refer to the stub, so the
// function itself is never emitted and therefore should not be marked.
if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global)
- MarkKnownEmitted(*this, Caller, Callee, Loc);
+ markKnownEmitted(*this, Caller, Callee, Loc, IsKnownEmitted);
} else {
// If we have
// host fn calls kernel fn calls host+device,
@@ -858,26 +702,27 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// that, when compiling for host, only HD functions actually called from the
// host get marked as known-emitted.
if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global)
- CUDACallGraph[Caller].insert({Callee, Loc});
+ DeviceCallGraph[Caller].insert({Callee, Loc});
}
- CUDADiagBuilder::Kind DiagKind = [&] {
+ DeviceDiagBuilder::Kind DiagKind = [this, Caller, Callee,
+ CallerKnownEmitted] {
switch (IdentifyCUDAPreference(Caller, Callee)) {
case CFP_Never:
- return CUDADiagBuilder::K_Immediate;
+ return DeviceDiagBuilder::K_Immediate;
case CFP_WrongSide:
assert(Caller && "WrongSide calls require a non-null caller");
// If we know the caller will be emitted, we know this wrong-side call
// will be emitted, so it's an immediate error. Otherwise, defer the
// error until we know the caller is emitted.
- return CallerKnownEmitted ? CUDADiagBuilder::K_ImmediateWithCallStack
- : CUDADiagBuilder::K_Deferred;
+ return CallerKnownEmitted ? DeviceDiagBuilder::K_ImmediateWithCallStack
+ : DeviceDiagBuilder::K_Deferred;
default:
- return CUDADiagBuilder::K_Nop;
+ return DeviceDiagBuilder::K_Nop;
}
}();
- if (DiagKind == CUDADiagBuilder::K_Nop)
+ if (DiagKind == DeviceDiagBuilder::K_Nop)
return true;
// Avoid emitting this error twice for the same location. Using a hashtable
@@ -887,13 +732,13 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
if (!LocsWithCUDACallDiags.insert({Caller, Loc}).second)
return true;
- CUDADiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this)
+ DeviceDiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this)
<< IdentifyCUDATarget(Callee) << Callee << IdentifyCUDATarget(Caller);
- CUDADiagBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl,
- Caller, *this)
+ DeviceDiagBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl,
+ Caller, *this)
<< Callee;
- return DiagKind != CUDADiagBuilder::K_Immediate &&
- DiagKind != CUDADiagBuilder::K_ImmediateWithCallStack;
+ return DiagKind != DeviceDiagBuilder::K_Immediate &&
+ DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack;
}
void Sema::CUDASetLambdaAttrs(CXXMethodDecl *Method) {
@@ -958,3 +803,16 @@ void Sema::inheritCUDATargetAttrs(FunctionDecl *FD,
copyAttrIfPresent<CUDAHostAttr>(*this, FD, TemplateFD);
copyAttrIfPresent<CUDADeviceAttr>(*this, FD, TemplateFD);
}
+
+std::string Sema::getCudaConfigureFuncName() const {
+ if (getLangOpts().HIP)
+ return "hipConfigureCall";
+
+ // New CUDA kernel launch sequence.
+ if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(),
+ CudaFeature::CUDA_USES_NEW_LAUNCH))
+ return "__cudaPushCallConfiguration";
+
+ // Legacy CUDA kernel configuration call
+ return "cudaConfigureCall";
+}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 2354ffe7fbcc..c473856f0b07 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -1,9 +1,8 @@
//===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -430,8 +429,9 @@ namespace {
// Callback to only accept typo corrections that can be a valid C++ member
// intializer: either a non-static field member or a base class.
-class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
- public:
+class NestedNameSpecifierValidatorCCC final
+ : public CorrectionCandidateCallback {
+public:
explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
: SRef(SRef) {}
@@ -439,6 +439,10 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this);
+ }
+
private:
Sema &SRef;
};
@@ -615,9 +619,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
+ NestedNameSpecifierValidatorCCC CCC(*this);
if (TypoCorrection Corrected = CorrectTypo(
- Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS,
- llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this),
+ Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, CCC,
CTK_ErrorRecovery, LookupCtx, EnteringContext)) {
if (LookupCtx) {
bool DroppedSpecifier =
@@ -884,7 +888,7 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
- TemplateTy Template,
+ TemplateTy OpaqueTemplate,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
@@ -894,11 +898,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (SS.isInvalid())
return true;
+ TemplateName Template = OpaqueTemplate.get();
+
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
- DependentTemplateName *DTN = Template.get().getAsDependentTemplateName();
+ DependentTemplateName *DTN = Template.getAsDependentTemplateName();
if (DTN && DTN->isIdentifier()) {
// Handle a dependent template specialization for which we cannot resolve
// the template name.
@@ -926,23 +932,28 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
return false;
}
- TemplateDecl *TD = Template.get().getAsTemplateDecl();
- if (Template.get().getAsOverloadedTemplate() || DTN ||
+ // If we assumed an undeclared identifier was a template name, try to
+ // typo-correct it now.
+ if (Template.getAsAssumedTemplateName() &&
+ resolveAssumedTemplateNameAsType(S, Template, TemplateNameLoc))
+ return true;
+
+ TemplateDecl *TD = Template.getAsTemplateDecl();
+ if (Template.getAsOverloadedTemplate() || DTN ||
isa<FunctionTemplateDecl>(TD) || isa<VarTemplateDecl>(TD)) {
SourceRange R(TemplateNameLoc, RAngleLoc);
if (SS.getRange().isValid())
R.setBegin(SS.getRange().getBegin());
Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
- << (TD && isa<VarTemplateDecl>(TD)) << Template.get() << R;
- NoteAllFoundTemplates(Template.get());
+ << (TD && isa<VarTemplateDecl>(TD)) << Template << R;
+ NoteAllFoundTemplates(Template);
return true;
}
// We were able to resolve the template name to an actual template.
// Build an appropriate nested-name-specifier.
- QualType T =
- CheckTemplateIdType(Template.get(), TemplateNameLoc, TemplateArgs);
+ QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
if (T.isNull())
return true;
@@ -950,7 +961,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// nested name specifiers.
if (!T->isDependentType() && !T->getAs<TagType>()) {
Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
- NoteAllFoundTemplates(Template.get());
+ NoteAllFoundTemplates(Template);
return true;
}
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 0b4645e11c34..f184eda2f273 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -1,9 +1,8 @@
//===--- SemaCast.cpp - Semantic Analysis for Casts -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -88,6 +87,7 @@ namespace {
void CheckDynamicCast();
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
+ void CheckBuiltinBitCast();
void updatePartOfExplicitCastFlags(CastExpr *CE) {
// Walk down from the CE to the OrigSrcExpr, and mark all immediate
@@ -285,7 +285,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
AngleBrackets));
case tok::kw_dynamic_cast: {
- // OpenCL C++ 1.0 s2.9: dynamic_cast is not supported.
+ // dynamic_cast is not supported in C++ for OpenCL.
if (getLangOpts().OpenCLCPlusPlus) {
return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported)
<< "dynamic_cast");
@@ -332,6 +332,38 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
}
+ExprResult Sema::ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &D,
+ ExprResult Operand,
+ SourceLocation RParenLoc) {
+ assert(!D.isInvalidType());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, Operand.get()->getType());
+ if (D.isInvalidType())
+ return ExprError();
+
+ return BuildBuiltinBitCastExpr(KWLoc, TInfo, Operand.get(), RParenLoc);
+}
+
+ExprResult Sema::BuildBuiltinBitCastExpr(SourceLocation KWLoc,
+ TypeSourceInfo *TSI, Expr *Operand,
+ SourceLocation RParenLoc) {
+ CastOperation Op(*this, TSI->getType(), Operand);
+ Op.OpRange = SourceRange(KWLoc, RParenLoc);
+ TypeLoc TL = TSI->getTypeLoc();
+ Op.DestRange = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
+
+ if (!Operand->isTypeDependent() && !TSI->getType()->isDependentType()) {
+ Op.CheckBuiltinBitCast();
+ if (Op.SrcExpr.isInvalid())
+ return ExprError();
+ }
+
+ BuiltinBitCastExpr *BCE =
+ new (Context) BuiltinBitCastExpr(Op.ResultType, Op.ValueKind, Op.Kind,
+ Op.SrcExpr.get(), TSI, KWLoc, RParenLoc);
+ return Op.complete(BCE);
+}
+
/// Try to diagnose a failed overloaded cast. Returns true if
/// diagnostics were emitted.
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
@@ -400,11 +432,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
break;
}
- S.Diag(range.getBegin(), msg)
- << CT << srcType << destType
- << range << src->getSourceRange();
-
- candidates.NoteCandidates(S, howManyCandidates, src);
+ candidates.NoteCandidates(
+ PartialDiagnosticAt(range.getBegin(),
+ S.PDiag(msg) << CT << srcType << destType << range
+ << src->getSourceRange()),
+ S, howManyCandidates, src);
return true;
}
@@ -2012,7 +2044,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (!CStyle) {
Self.CheckCompatibleReinterpretCast(SrcType, DestType,
- /*isDereference=*/false, OpRange);
+ /*IsDereference=*/false, OpRange);
}
// C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
@@ -2213,7 +2245,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
/*CheckObjCLifetime=*/CStyle))
SuccessResult = getCastAwayConstnessCastKind(CACK, msg);
- if (IsLValueCast) {
+ if (IsAddressSpaceConversion(SrcType, DestType)) {
+ Kind = CK_AddressSpaceConversion;
+ assert(SrcType->isPointerType() && DestType->isPointerType());
+ if (!CStyle &&
+ !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf(
+ SrcType->getPointeeType().getQualifiers())) {
+ SuccessResult = TC_Failed;
+ }
+ } else if (IsLValueCast) {
Kind = CK_LValueBitCast;
} else if (DestType->isObjCObjectPointerType()) {
Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr);
@@ -2223,8 +2263,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
} else {
Kind = CK_BitCast;
}
- } else if (IsAddressSpaceConversion(SrcType, DestType)) {
- Kind = CK_AddressSpaceConversion;
} else {
Kind = CK_BitCast;
}
@@ -2279,23 +2317,80 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return SuccessResult;
}
+static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
+ QualType DestType, bool CStyle,
+ unsigned &msg) {
+ if (!Self.getLangOpts().OpenCL)
+ // FIXME: As compiler doesn't have any information about overlapping addr
+ // spaces at the moment we have to be permissive here.
+ return TC_NotApplicable;
+ // Even though the logic below is general enough and can be applied to
+ // non-OpenCL mode too, we fast-path above because no other languages
+ // define overlapping address spaces currently.
+ auto SrcType = SrcExpr.get()->getType();
+ auto SrcPtrType = SrcType->getAs<PointerType>();
+ if (!SrcPtrType)
+ return TC_NotApplicable;
+ auto DestPtrType = DestType->getAs<PointerType>();
+ if (!DestPtrType)
+ return TC_NotApplicable;
+ auto SrcPointeeType = SrcPtrType->getPointeeType();
+ auto DestPointeeType = DestPtrType->getPointeeType();
+ if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace())
+ return TC_NotApplicable;
+ if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
+ msg = diag::err_bad_cxx_cast_addr_space_mismatch;
+ return TC_Failed;
+ }
+ auto SrcPointeeTypeWithoutAS =
+ Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType());
+ auto DestPointeeTypeWithoutAS =
+ Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType());
+ return Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
+ DestPointeeTypeWithoutAS)
+ ? TC_Success
+ : TC_NotApplicable;
+}
+
void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
// In OpenCL only conversions between pointers to objects in overlapping
// addr spaces are allowed. v2.0 s6.5.5 - Generic addr space overlaps
// with any named one, except for constant.
+
+ // Converting the top level pointee addrspace is permitted for compatible
+ // addrspaces (such as 'generic int *' to 'local int *' or vice versa), but
+ // if any of the nested pointee addrspaces differ, we emit a warning
+ // regardless of addrspace compatibility. This makes
+ // local int ** p;
+ // return (generic int **) p;
+ // warn even though local -> generic is permitted.
if (Self.getLangOpts().OpenCL) {
- auto SrcPtrType = SrcType->getAs<PointerType>();
- if (!SrcPtrType)
- return;
- auto DestPtrType = DestType->getAs<PointerType>();
- if (!DestPtrType)
- return;
- if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
- Self.Diag(OpRange.getBegin(),
- diag::err_typecheck_incompatible_address_space)
- << SrcType << DestType << Sema::AA_Casting
- << SrcExpr.get()->getSourceRange();
- SrcExpr = ExprError();
+ const Type *DestPtr, *SrcPtr;
+ bool Nested = false;
+ unsigned DiagID = diag::err_typecheck_incompatible_address_space;
+ DestPtr = Self.getASTContext().getCanonicalType(DestType.getTypePtr()),
+ SrcPtr = Self.getASTContext().getCanonicalType(SrcType.getTypePtr());
+
+ while (isa<PointerType>(DestPtr) && isa<PointerType>(SrcPtr)) {
+ const PointerType *DestPPtr = cast<PointerType>(DestPtr);
+ const PointerType *SrcPPtr = cast<PointerType>(SrcPtr);
+ QualType DestPPointee = DestPPtr->getPointeeType();
+ QualType SrcPPointee = SrcPPtr->getPointeeType();
+ if (Nested ? DestPPointee.getAddressSpace() !=
+ SrcPPointee.getAddressSpace()
+ : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) {
+ Self.Diag(OpRange.getBegin(), DiagID)
+ << SrcType << DestType << Sema::AA_Casting
+ << SrcExpr.get()->getSourceRange();
+ if (!Nested)
+ SrcExpr = ExprError();
+ return;
+ }
+
+ DestPtr = DestPPtr->getPointeeType().getTypePtr();
+ SrcPtr = SrcPPtr->getPointeeType().getTypePtr();
+ Nested = true;
+ DiagID = diag::ext_nested_pointer_qualifier_mismatch;
}
}
}
@@ -2373,30 +2468,39 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
// listed above, the interpretation that appears first in the list is used,
// even if a cast resulting from that interpretation is ill-formed.
// In plain language, this means trying a const_cast ...
+ // Note that for address space we check compatibility after const_cast.
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType,
- /*CStyle*/true, msg);
+ /*CStyle*/ true, msg);
if (SrcExpr.isInvalid())
return;
if (isValidCast(tcr))
Kind = CK_NoOp;
- Sema::CheckedConversionKind CCK
- = FunctionalStyle? Sema::CCK_FunctionalCast
- : Sema::CCK_CStyleCast;
+ Sema::CheckedConversionKind CCK =
+ FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
- // ... or if that is not possible, a static_cast, ignoring const, ...
- tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange,
- msg, Kind, BasePath, ListInitialization);
+ tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg);
if (SrcExpr.isInvalid())
return;
+ if (isValidCast(tcr))
+ Kind = CK_AddressSpaceConversion;
+
if (tcr == TC_NotApplicable) {
- // ... and finally a reinterpret_cast, ignoring const.
- tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true,
- OpRange, msg, Kind);
+ // ... or if that is not possible, a static_cast, ignoring const, ...
+ tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind,
+ BasePath, ListInitialization);
if (SrcExpr.isInvalid())
return;
+
+ if (tcr == TC_NotApplicable) {
+ // ... and finally a reinterpret_cast, ignoring const.
+ tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true,
+ OpRange, msg, Kind);
+ if (SrcExpr.isInvalid())
+ return;
+ }
}
}
@@ -2427,8 +2531,6 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
}
}
- checkAddressSpaceCast(SrcExpr.get()->getType(), DestType);
-
if (isValidCast(tcr)) {
if (Kind == CK_BitCast)
checkCastAlign();
@@ -2695,6 +2797,43 @@ void CastOperation::CheckCStyleCast() {
checkCastAlign();
}
+void CastOperation::CheckBuiltinBitCast() {
+ QualType SrcType = SrcExpr.get()->getType();
+ if (SrcExpr.get()->isRValue())
+ SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
+ /*IsLValueReference=*/false);
+
+ CharUnits DestSize = Self.Context.getTypeSizeInChars(DestType);
+ CharUnits SourceSize = Self.Context.getTypeSizeInChars(SrcType);
+ if (DestSize != SourceSize) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_type_size_mismatch)
+ << (int)SourceSize.getQuantity() << (int)DestSize.getQuantity();
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!DestType.isTriviallyCopyableType(Self.Context)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable)
+ << 1;
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (!SrcType.isTriviallyCopyableType(Self.Context)) {
+ Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable)
+ << 0;
+ SrcExpr = ExprError();
+ return;
+ }
+
+ if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+ Kind = CK_NoOp;
+ return;
+ }
+
+ Kind = CK_LValueToRValueBitCast;
+}
+
/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either
/// const, volatile or both.
static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
@@ -2742,7 +2881,7 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
Op.OpRange = SourceRange(LPLoc, CastExpr->getEndLoc());
if (getLangOpts().CPlusPlus) {
- Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false,
+ Op.CheckCXXCStyleCast(/*FunctionalCast=*/ false,
isa<InitListExpr>(CastExpr));
} else {
Op.CheckCStyleCast();
@@ -2769,7 +2908,7 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getEndLoc());
- Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false);
+ Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false);
if (Op.SrcExpr.isInvalid())
return ExprError();
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 8dc1fdb76988..f9f82cdeef43 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1,9 +1,8 @@
//===- SemaChecking.cpp - Extra Semantic Checking -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -85,6 +84,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/Locale.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -191,6 +191,16 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
return false;
}
+/// Check the number of arguments, and set the result type to
+/// the argument type.
+static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 1))
+ return true;
+
+ TheCall->setType(TheCall->getArg(0)->getType());
+ return false;
+}
+
static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 3))
return true;
@@ -236,47 +246,6 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) {
return false;
}
-static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl,
- CallExpr *TheCall, unsigned SizeIdx,
- unsigned DstSizeIdx,
- StringRef LikelyMacroName) {
- if (TheCall->getNumArgs() <= SizeIdx ||
- TheCall->getNumArgs() <= DstSizeIdx)
- return;
-
- const Expr *SizeArg = TheCall->getArg(SizeIdx);
- const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx);
-
- Expr::EvalResult SizeResult, DstSizeResult;
-
- // find out if both sizes are known at compile time
- if (!SizeArg->EvaluateAsInt(SizeResult, S.Context) ||
- !DstSizeArg->EvaluateAsInt(DstSizeResult, S.Context))
- return;
-
- llvm::APSInt Size = SizeResult.Val.getInt();
- llvm::APSInt DstSize = DstSizeResult.Val.getInt();
-
- if (Size.ule(DstSize))
- return;
-
- // Confirmed overflow, so generate the diagnostic.
- StringRef FunctionName = FDecl->getName();
- SourceLocation SL = TheCall->getBeginLoc();
- SourceManager &SM = S.getSourceManager();
- // If we're in an expansion of a macro whose name corresponds to this builtin,
- // use the simple macro name and location.
- if (SL.isMacroID() && Lexer::getImmediateMacroName(SL, SM, S.getLangOpts()) ==
- LikelyMacroName) {
- FunctionName = LikelyMacroName;
- SL = SM.getImmediateMacroCallerLoc(SL);
- }
-
- S.Diag(SL, diag::warn_memcpy_chk_overflow)
- << FunctionName << DstSize.toString(/*Radix=*/10)
- << Size.toString(/*Radix=*/10);
-}
-
static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
if (checkArgCount(S, BuiltinCall, 2))
return true;
@@ -340,6 +309,149 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
return false;
}
+/// Check a call to BuiltinID for buffer overflows. If BuiltinID is a
+/// __builtin_*_chk function, then use the object size argument specified in the
+/// source. Otherwise, infer the object size using __builtin_object_size.
+void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
+ CallExpr *TheCall) {
+ // FIXME: There are some more useful checks we could be doing here:
+ // - Analyze the format string of sprintf to see how much of buffer is used.
+ // - Evaluate strlen of strcpy arguments, use as object size.
+
+ if (TheCall->isValueDependent() || TheCall->isTypeDependent() ||
+ isConstantEvaluated())
+ return;
+
+ unsigned BuiltinID = FD->getBuiltinID(/*ConsiderWrappers=*/true);
+ if (!BuiltinID)
+ return;
+
+ unsigned DiagID = 0;
+ bool IsChkVariant = false;
+ unsigned SizeIndex, ObjectIndex;
+ switch (BuiltinID) {
+ default:
+ return;
+ case Builtin::BI__builtin___memcpy_chk:
+ case Builtin::BI__builtin___memmove_chk:
+ case Builtin::BI__builtin___memset_chk:
+ case Builtin::BI__builtin___strlcat_chk:
+ case Builtin::BI__builtin___strlcpy_chk:
+ case Builtin::BI__builtin___strncat_chk:
+ case Builtin::BI__builtin___strncpy_chk:
+ case Builtin::BI__builtin___stpncpy_chk:
+ case Builtin::BI__builtin___memccpy_chk: {
+ DiagID = diag::warn_builtin_chk_overflow;
+ IsChkVariant = true;
+ SizeIndex = TheCall->getNumArgs() - 2;
+ ObjectIndex = TheCall->getNumArgs() - 1;
+ break;
+ }
+
+ case Builtin::BI__builtin___snprintf_chk:
+ case Builtin::BI__builtin___vsnprintf_chk: {
+ DiagID = diag::warn_builtin_chk_overflow;
+ IsChkVariant = true;
+ SizeIndex = 1;
+ ObjectIndex = 3;
+ break;
+ }
+
+ case Builtin::BIstrncat:
+ case Builtin::BI__builtin_strncat:
+ case Builtin::BIstrncpy:
+ case Builtin::BI__builtin_strncpy:
+ case Builtin::BIstpncpy:
+ case Builtin::BI__builtin_stpncpy: {
+ // Whether these functions overflow depends on the runtime strlen of the
+ // string, not just the buffer size, so emitting the "always overflow"
+ // diagnostic isn't quite right. We should still diagnose passing a buffer
+ // size larger than the destination buffer though; this is a runtime abort
+ // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise.
+ DiagID = diag::warn_fortify_source_size_mismatch;
+ SizeIndex = TheCall->getNumArgs() - 1;
+ ObjectIndex = 0;
+ break;
+ }
+
+ case Builtin::BImemcpy:
+ case Builtin::BI__builtin_memcpy:
+ case Builtin::BImemmove:
+ case Builtin::BI__builtin_memmove:
+ case Builtin::BImemset:
+ case Builtin::BI__builtin_memset: {
+ DiagID = diag::warn_fortify_source_overflow;
+ SizeIndex = TheCall->getNumArgs() - 1;
+ ObjectIndex = 0;
+ break;
+ }
+ case Builtin::BIsnprintf:
+ case Builtin::BI__builtin_snprintf:
+ case Builtin::BIvsnprintf:
+ case Builtin::BI__builtin_vsnprintf: {
+ DiagID = diag::warn_fortify_source_size_mismatch;
+ SizeIndex = 1;
+ ObjectIndex = 0;
+ break;
+ }
+ }
+
+ llvm::APSInt ObjectSize;
+ // For __builtin___*_chk, the object size is explicitly provided by the caller
+ // (usually using __builtin_object_size). Use that value to check this call.
+ if (IsChkVariant) {
+ Expr::EvalResult Result;
+ Expr *SizeArg = TheCall->getArg(ObjectIndex);
+ if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
+ return;
+ ObjectSize = Result.Val.getInt();
+
+ // Otherwise, try to evaluate an imaginary call to __builtin_object_size.
+ } else {
+ // If the parameter has a pass_object_size attribute, then we should use its
+ // (potentially) more strict checking mode. Otherwise, conservatively assume
+ // type 0.
+ int BOSType = 0;
+ if (const auto *POS =
+ FD->getParamDecl(ObjectIndex)->getAttr<PassObjectSizeAttr>())
+ BOSType = POS->getType();
+
+ Expr *ObjArg = TheCall->getArg(ObjectIndex);
+ uint64_t Result;
+ if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType))
+ return;
+ // Get the object size in the target's size_t width.
+ const TargetInfo &TI = getASTContext().getTargetInfo();
+ unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
+ ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth);
+ }
+
+ // Evaluate the number of bytes of the object that this call will use.
+ Expr::EvalResult Result;
+ Expr *UsedSizeArg = TheCall->getArg(SizeIndex);
+ if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext()))
+ return;
+ llvm::APSInt UsedSize = Result.Val.getInt();
+
+ if (UsedSize.ule(ObjectSize))
+ return;
+
+ StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID);
+ // Skim off the details of whichever builtin was called to produce a better
+ // diagnostic, as it's unlikley that the user wrote the __builtin explicitly.
+ if (IsChkVariant) {
+ FunctionName = FunctionName.drop_front(std::strlen("__builtin___"));
+ FunctionName = FunctionName.drop_back(std::strlen("_chk"));
+ } else if (FunctionName.startswith("__builtin_")) {
+ FunctionName = FunctionName.drop_front(std::strlen("__builtin_"));
+ }
+
+ DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
+ PDiag(DiagID)
+ << FunctionName << ObjectSize.toString(/*Radix=*/10)
+ << UsedSize.toString(/*Radix=*/10));
+}
+
static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
Scope::ScopeFlags NeededScopeFlags,
unsigned DiagID) {
@@ -1077,6 +1189,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaBuiltinAssumeAligned(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size:
if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
return ExprError();
@@ -1098,10 +1211,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (checkArgCount(*this, TheCall, 1)) return true;
TheCall->setType(Context.IntTy);
break;
- case Builtin::BI__builtin_constant_p:
+ case Builtin::BI__builtin_constant_p: {
if (checkArgCount(*this, TheCall, 1)) return true;
+ ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+ if (Arg.isInvalid()) return true;
+ TheCall->setArg(0, Arg.get());
TheCall->setType(Context.IntTy);
break;
+ }
case Builtin::BI__builtin_launder:
return SemaBuiltinLaunder(*this, TheCall);
case Builtin::BI__sync_fetch_and_add:
@@ -1302,41 +1419,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(Context.IntTy);
break;
}
-
- // check secure string manipulation functions where overflows
- // are detectable at compile time
- case Builtin::BI__builtin___memcpy_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memcpy");
- break;
- case Builtin::BI__builtin___memmove_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memmove");
- break;
- case Builtin::BI__builtin___memset_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memset");
- break;
- case Builtin::BI__builtin___strlcat_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strlcat");
- break;
- case Builtin::BI__builtin___strlcpy_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strlcpy");
- break;
- case Builtin::BI__builtin___strncat_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strncat");
- break;
- case Builtin::BI__builtin___strncpy_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strncpy");
- break;
- case Builtin::BI__builtin___stpncpy_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "stpncpy");
- break;
- case Builtin::BI__builtin___memccpy_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 3, 4, "memccpy");
- break;
- case Builtin::BI__builtin___snprintf_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3, "snprintf");
- break;
- case Builtin::BI__builtin___vsnprintf_chk:
- SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3, "vsnprintf");
+ case Builtin::BI__builtin_preserve_access_index:
+ if (SemaBuiltinPreserveAI(*this, TheCall))
+ return ExprError();
break;
case Builtin::BI__builtin_call_with_static_chain:
if (SemaBuiltinCallWithStaticChain(*this, TheCall))
@@ -1806,6 +1891,16 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
BuiltinID == AArch64::BI__builtin_arm_wsr64)
return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
+ // Memory Tagging Extensions (MTE) Intrinsics
+ if (BuiltinID == AArch64::BI__builtin_arm_irg ||
+ BuiltinID == AArch64::BI__builtin_arm_addg ||
+ BuiltinID == AArch64::BI__builtin_arm_gmi ||
+ BuiltinID == AArch64::BI__builtin_arm_ldg ||
+ BuiltinID == AArch64::BI__builtin_arm_stg ||
+ BuiltinID == AArch64::BI__builtin_arm_subp) {
+ return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall);
+ }
+
if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
BuiltinID == AArch64::BI__builtin_arm_rsrp ||
BuiltinID == AArch64::BI__builtin_arm_wsr ||
@@ -2620,8 +2715,7 @@ bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
const TargetInfo &TI = Context.getTargetInfo();
const BuiltinAndString *FC =
- std::lower_bound(std::begin(ValidCPU), std::end(ValidCPU), BuiltinID,
- LowerBoundCmp);
+ llvm::lower_bound(ValidCPU, BuiltinID, LowerBoundCmp);
if (FC != std::end(ValidCPU) && FC->BuiltinID == BuiltinID) {
const TargetOptions &Opts = TI.getTargetOpts();
StringRef CPU = Opts.CPU;
@@ -2637,8 +2731,7 @@ bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
}
const BuiltinAndString *FH =
- std::lower_bound(std::begin(ValidHVX), std::end(ValidHVX), BuiltinID,
- LowerBoundCmp);
+ llvm::lower_bound(ValidHVX, BuiltinID, LowerBoundCmp);
if (FH != std::end(ValidHVX) && FH->BuiltinID == BuiltinID) {
if (!TI.hasFeature("hvx"))
return Diag(TheCall->getBeginLoc(),
@@ -2867,11 +2960,8 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
true);
(void)SortOnce;
- const BuiltinInfo *F =
- std::lower_bound(std::begin(Infos), std::end(Infos), BuiltinID,
- [](const BuiltinInfo &BI, unsigned BuiltinID) {
- return BI.BuiltinID < BuiltinID;
- });
+ const BuiltinInfo *F = llvm::partition_point(
+ Infos, [=](const BuiltinInfo &BI) { return BI.BuiltinID < BuiltinID; });
if (F == std::end(Infos) || F->BuiltinID != BuiltinID)
return false;
@@ -2955,6 +3045,8 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// These intrinsics take an unsigned 5 bit immediate.
// The first block of intrinsics actually have an unsigned 5 bit field,
// not a df/n field.
+ case Mips::BI__builtin_msa_cfcmsa:
+ case Mips::BI__builtin_msa_ctcmsa: i = 0; l = 0; u = 31; break;
case Mips::BI__builtin_msa_clei_u_b:
case Mips::BI__builtin_msa_clei_u_h:
case Mips::BI__builtin_msa_clei_u_w:
@@ -3201,6 +3293,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
case SystemZ::BI__builtin_s390_vfmaxsb:
case SystemZ::BI__builtin_s390_vfmindb:
case SystemZ::BI__builtin_s390_vfmaxdb: i = 2; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vsld: i = 2; l = 0; u = 7; break;
+ case SystemZ::BI__builtin_s390_vsrd: i = 2; l = 0; u = 7; break;
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
@@ -3299,6 +3393,8 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_cvtss2sd_round_mask:
case X86::BI__builtin_ia32_getexpsd128_round_mask:
case X86::BI__builtin_ia32_getexpss128_round_mask:
+ case X86::BI__builtin_ia32_getmantpd512_mask:
+ case X86::BI__builtin_ia32_getmantps512_mask:
case X86::BI__builtin_ia32_maxsd_round_mask:
case X86::BI__builtin_ia32_maxss_round_mask:
case X86::BI__builtin_ia32_minsd_round_mask:
@@ -3321,6 +3417,8 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
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_getmantsd_round_mask:
+ case X86::BI__builtin_ia32_getmantss_round_mask:
case X86::BI__builtin_ia32_rangepd512_mask:
case X86::BI__builtin_ia32_rangeps512_mask:
case X86::BI__builtin_ia32_rangesd128_round_mask:
@@ -3364,9 +3462,13 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_cvtdq2ps512_mask:
case X86::BI__builtin_ia32_cvtudq2ps512_mask:
case X86::BI__builtin_ia32_cvtpd2ps512_mask:
+ case X86::BI__builtin_ia32_cvtpd2dq512_mask:
case X86::BI__builtin_ia32_cvtpd2qq512_mask:
+ case X86::BI__builtin_ia32_cvtpd2udq512_mask:
case X86::BI__builtin_ia32_cvtpd2uqq512_mask:
+ case X86::BI__builtin_ia32_cvtps2dq512_mask:
case X86::BI__builtin_ia32_cvtps2qq512_mask:
+ case X86::BI__builtin_ia32_cvtps2udq512_mask:
case X86::BI__builtin_ia32_cvtps2uqq512_mask:
case X86::BI__builtin_ia32_cvtqq2pd512_mask:
case X86::BI__builtin_ia32_cvtqq2ps512_mask:
@@ -3387,8 +3489,6 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_scalefps512_mask:
case X86::BI__builtin_ia32_scalefsd_round_mask:
case X86::BI__builtin_ia32_scalefss_round_mask:
- case X86::BI__builtin_ia32_getmantpd512_mask:
- case X86::BI__builtin_ia32_getmantps512_mask:
case X86::BI__builtin_ia32_cvtsd2ss_round_mask:
case X86::BI__builtin_ia32_sqrtsd_round_mask:
case X86::BI__builtin_ia32_sqrtss_round_mask:
@@ -3417,11 +3517,6 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
ArgNum = 4;
HasRC = true;
break;
- case X86::BI__builtin_ia32_getmantsd_round_mask:
- case X86::BI__builtin_ia32_getmantss_round_mask:
- ArgNum = 5;
- HasRC = true;
- break;
}
llvm::APSInt Result;
@@ -3906,6 +4001,8 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_scatterpfqps:
i = 4; l = 2; u = 3;
break;
+ case X86::BI__builtin_ia32_reducesd_mask:
+ case X86::BI__builtin_ia32_reducess_mask:
case X86::BI__builtin_ia32_rndscalesd_round_mask:
case X86::BI__builtin_ia32_rndscaless_round_mask:
i = 4; l = 0; u = 255;
@@ -3975,7 +4072,8 @@ static void CheckNonNullArgument(Sema &S,
SourceLocation CallSiteLoc) {
if (CheckNonNullExpr(S, ArgExpr))
S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr,
- S.PDiag(diag::warn_null_arg) << ArgExpr->getSourceRange());
+ S.PDiag(diag::warn_null_arg)
+ << ArgExpr->getSourceRange());
}
bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
@@ -4045,6 +4143,9 @@ static void CheckNonNullArguments(Sema &S,
SourceLocation CallSiteLoc) {
assert((FDecl || Proto) && "Need a function declaration or prototype");
+ // Already checked by by constant evaluator.
+ if (S.isConstantEvaluated())
+ return;
// Check the attributes attached to the method/function itself.
llvm::SmallBitVector NonNullArgs;
if (FDecl) {
@@ -4802,7 +4903,7 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
/// We have a call to a function like __sync_fetch_and_add, which is an
/// overloaded function based on the pointer type of its first argument.
-/// The main ActOnCallExpr routines have already promoted the types of
+/// The main BuildCallExpr routines have already promoted the types of
/// arguments because all of these calls are prototyped as void(...).
///
/// This function goes through and does final semantic checking for these
@@ -5149,15 +5250,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
}
// Create a new DeclRefExpr to refer to the new decl.
- DeclRefExpr* NewDRE = DeclRefExpr::Create(
- Context,
- DRE->getQualifierLoc(),
- SourceLocation(),
- NewBuiltinDecl,
- /*enclosing*/ false,
- DRE->getLocation(),
- Context.BuiltinFnTy,
- DRE->getValueKind());
+ DeclRefExpr *NewDRE = DeclRefExpr::Create(
+ Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl,
+ /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy,
+ DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse());
// Set the callee in the CallExpr.
// FIXME: This loses syntactic information.
@@ -5980,6 +6076,8 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
/// TheCall is a constant expression in the range [Low, High].
bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
int Low, int High, bool RangeIsError) {
+ if (isConstantEvaluated())
+ return false;
llvm::APSInt Result;
// We can't check the value of a dependent argument.
@@ -6029,6 +6127,160 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum,
return false;
}
+/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
+bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) {
+ if (BuiltinID == AArch64::BI__builtin_arm_irg) {
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+ Expr *Arg0 = TheCall->getArg(0);
+ Expr *Arg1 = TheCall->getArg(1);
+
+ ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+ if (FirstArg.isInvalid())
+ return true;
+ QualType FirstArgType = FirstArg.get()->getType();
+ if (!FirstArgType->isAnyPointerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+ << "first" << FirstArgType << Arg0->getSourceRange();
+ TheCall->setArg(0, FirstArg.get());
+
+ ExprResult SecArg = DefaultLvalueConversion(Arg1);
+ if (SecArg.isInvalid())
+ return true;
+ QualType SecArgType = SecArg.get()->getType();
+ if (!SecArgType->isIntegerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
+ << "second" << SecArgType << Arg1->getSourceRange();
+
+ // Derive the return type from the pointer argument.
+ TheCall->setType(FirstArgType);
+ return false;
+ }
+
+ if (BuiltinID == AArch64::BI__builtin_arm_addg) {
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+
+ Expr *Arg0 = TheCall->getArg(0);
+ ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+ if (FirstArg.isInvalid())
+ return true;
+ QualType FirstArgType = FirstArg.get()->getType();
+ if (!FirstArgType->isAnyPointerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+ << "first" << FirstArgType << Arg0->getSourceRange();
+ TheCall->setArg(0, FirstArg.get());
+
+ // Derive the return type from the pointer argument.
+ TheCall->setType(FirstArgType);
+
+ // Second arg must be an constant in range [0,15]
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
+ }
+
+ if (BuiltinID == AArch64::BI__builtin_arm_gmi) {
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+ Expr *Arg0 = TheCall->getArg(0);
+ Expr *Arg1 = TheCall->getArg(1);
+
+ ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+ if (FirstArg.isInvalid())
+ return true;
+ QualType FirstArgType = FirstArg.get()->getType();
+ if (!FirstArgType->isAnyPointerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+ << "first" << FirstArgType << Arg0->getSourceRange();
+
+ QualType SecArgType = Arg1->getType();
+ if (!SecArgType->isIntegerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer)
+ << "second" << SecArgType << Arg1->getSourceRange();
+ TheCall->setType(Context.IntTy);
+ return false;
+ }
+
+ if (BuiltinID == AArch64::BI__builtin_arm_ldg ||
+ BuiltinID == AArch64::BI__builtin_arm_stg) {
+ if (checkArgCount(*this, TheCall, 1))
+ return true;
+ Expr *Arg0 = TheCall->getArg(0);
+ ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0);
+ if (FirstArg.isInvalid())
+ return true;
+
+ QualType FirstArgType = FirstArg.get()->getType();
+ if (!FirstArgType->isAnyPointerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer)
+ << "first" << FirstArgType << Arg0->getSourceRange();
+ TheCall->setArg(0, FirstArg.get());
+
+ // Derive the return type from the pointer argument.
+ if (BuiltinID == AArch64::BI__builtin_arm_ldg)
+ TheCall->setType(FirstArgType);
+ return false;
+ }
+
+ if (BuiltinID == AArch64::BI__builtin_arm_subp) {
+ Expr *ArgA = TheCall->getArg(0);
+ Expr *ArgB = TheCall->getArg(1);
+
+ ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA);
+ ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB);
+
+ if (ArgExprA.isInvalid() || ArgExprB.isInvalid())
+ return true;
+
+ QualType ArgTypeA = ArgExprA.get()->getType();
+ QualType ArgTypeB = ArgExprB.get()->getType();
+
+ auto isNull = [&] (Expr *E) -> bool {
+ return E->isNullPointerConstant(
+ Context, Expr::NPC_ValueDependentIsNotNull); };
+
+ // argument should be either a pointer or null
+ if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA))
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
+ << "first" << ArgTypeA << ArgA->getSourceRange();
+
+ if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB))
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer)
+ << "second" << ArgTypeB << ArgB->getSourceRange();
+
+ // Ensure Pointee types are compatible
+ if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) &&
+ ArgTypeB->isAnyPointerType() && !isNull(ArgB)) {
+ QualType pointeeA = ArgTypeA->getPointeeType();
+ QualType pointeeB = ArgTypeB->getPointeeType();
+ if (!Context.typesAreCompatible(
+ Context.getCanonicalType(pointeeA).getUnqualifiedType(),
+ Context.getCanonicalType(pointeeB).getUnqualifiedType())) {
+ return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible)
+ << ArgTypeA << ArgTypeB << ArgA->getSourceRange()
+ << ArgB->getSourceRange();
+ }
+ }
+
+ // at least one argument should be pointer type
+ if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType())
+ return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer)
+ << ArgTypeA << ArgTypeB << ArgA->getSourceRange();
+
+ if (isNull(ArgA)) // adopt type of the other pointer
+ ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer);
+
+ if (isNull(ArgB))
+ ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer);
+
+ TheCall->setArg(0, ArgExprA.get());
+ TheCall->setArg(1, ArgExprB.get());
+ TheCall->setType(Context.LongLongTy);
+ return false;
+ }
+ assert(false && "Unhandled ARM MTE intrinsic");
+ return true;
+}
+
/// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
/// TheCall is an ARM/AArch64 special register string literal.
bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
@@ -6332,6 +6584,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg,
llvm::APSInt Offset) {
+ if (S.isConstantEvaluated())
+ return SLCT_NotALiteral;
tryAgain:
assert(Offset.isSigned() && "invalid offset");
@@ -6361,7 +6615,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
bool CheckLeft = true, CheckRight = true;
bool Cond;
- if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext())) {
+ if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext(),
+ S.isConstantEvaluated())) {
if (Cond)
CheckRight = false;
else
@@ -6562,8 +6817,10 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (BinOp->isAdditiveOp()) {
Expr::EvalResult LResult, RResult;
- bool LIsInt = BinOp->getLHS()->EvaluateAsInt(LResult, S.Context);
- bool RIsInt = BinOp->getRHS()->EvaluateAsInt(RResult, S.Context);
+ bool LIsInt = BinOp->getLHS()->EvaluateAsInt(
+ LResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated());
+ bool RIsInt = BinOp->getRHS()->EvaluateAsInt(
+ RResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated());
if (LIsInt != RIsInt) {
BinaryOperatorKind BinOpKind = BinOp->getOpcode();
@@ -6589,7 +6846,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr());
if (UnaOp->getOpcode() == UO_AddrOf && ASE) {
Expr::EvalResult IndexResult;
- if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) {
+ if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context,
+ Expr::SE_NoSideEffects,
+ S.isConstantEvaluated())) {
sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add,
/*RHS is int*/ true);
E = ASE->getBase();
@@ -7651,7 +7910,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
startSpecifier, specifierLen);
// Check the length modifier is valid with the given conversion specifier.
- if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+ S.getLangOpts()))
HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
diag::warn_format_nonsensical_length);
else if (!FS.hasStandardLengthModifier())
@@ -8155,7 +8415,8 @@ bool CheckScanfHandler::HandleScanfSpecifier(
}
// Check the length modifier is valid with the given conversion specifier.
- if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+ S.getLangOpts()))
HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
diag::warn_format_nonsensical_length);
else if (!FS.hasStandardLengthModifier())
@@ -9172,23 +9433,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
getContainedDynamicClass(PointeeTy, IsContained)) {
unsigned OperationType = 0;
+ const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp;
// "overwritten" if we're warning about the destination for any call
// but memcmp; otherwise a verb appropriate to the call.
- if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
+ if (ArgIdx != 0 || IsCmp) {
if (BId == Builtin::BImemcpy)
OperationType = 1;
else if(BId == Builtin::BImemmove)
OperationType = 2;
- else if (BId == Builtin::BImemcmp)
+ else if (IsCmp)
OperationType = 3;
}
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_dyn_class_memaccess)
- << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
- << FnName << IsContained << ContainedRD << OperationType
- << Call->getCallee()->getSourceRange());
+ DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_dyn_class_memaccess)
+ << (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName
+ << IsContained << ContainedRD << OperationType
+ << Call->getCallee()->getSourceRange());
} else if (PointeeTy.hasNonTrivialObjCLifetime() &&
BId != Builtin::BImemset)
DiagRuntimeBehavior(
@@ -9667,12 +9928,13 @@ static QualType GetExprType(const Expr *E) {
/// range of values it might take.
///
/// \param MaxWidth - the width to which the value will be truncated
-static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
+static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
+ bool InConstantContext) {
E = E->IgnoreParens();
// Try a full evaluation first.
Expr::EvalResult result;
- if (E->EvaluateAsRValue(result, C))
+ if (E->EvaluateAsRValue(result, C, InConstantContext))
return GetValueRange(C, result.Val, GetExprType(E), MaxWidth);
// I think we only want to look through implicit casts here; if the
@@ -9680,7 +9942,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// being of the new, wider type.
if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) {
if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
- return GetExprRange(C, CE->getSubExpr(), MaxWidth);
+ return GetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext);
IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));
@@ -9691,9 +9953,9 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
if (!isIntegerCast)
return OutputTypeRange;
- IntRange SubRange
- = GetExprRange(C, CE->getSubExpr(),
- std::min(MaxWidth, OutputTypeRange.Width));
+ IntRange SubRange = GetExprRange(C, CE->getSubExpr(),
+ std::min(MaxWidth, OutputTypeRange.Width),
+ InConstantContext);
// Bail out if the subexpr's range is as wide as the cast type.
if (SubRange.Width >= OutputTypeRange.Width)
@@ -9709,13 +9971,15 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// If we can fold the condition, just take that operand.
bool CondResult;
if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
- return GetExprRange(C, CondResult ? CO->getTrueExpr()
- : CO->getFalseExpr(),
- MaxWidth);
+ return GetExprRange(C,
+ CondResult ? CO->getTrueExpr() : CO->getFalseExpr(),
+ MaxWidth, InConstantContext);
// Otherwise, conservatively merge.
- IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth);
- IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth);
+ IntRange L =
+ GetExprRange(C, CO->getTrueExpr(), MaxWidth, InConstantContext);
+ IntRange R =
+ GetExprRange(C, CO->getFalseExpr(), MaxWidth, InConstantContext);
return IntRange::join(L, R);
}
@@ -9751,7 +10015,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// been coerced to the LHS type.
case BO_Assign:
// TODO: bitfields?
- return GetExprRange(C, BO->getRHS(), MaxWidth);
+ return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext);
// Operations with opaque sources are black-listed.
case BO_PtrMemD:
@@ -9761,8 +10025,9 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// Bitwise-and uses the *infinum* of the two source ranges.
case BO_And:
case BO_AndAssign:
- return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth),
- GetExprRange(C, BO->getRHS(), MaxWidth));
+ return IntRange::meet(
+ GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext),
+ GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext));
// Left shift gets black-listed based on a judgement call.
case BO_Shl:
@@ -9783,7 +10048,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// Right shift by a constant can narrow its left argument.
case BO_Shr:
case BO_ShrAssign: {
- IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext);
// If the shift amount is a positive constant, drop the width by
// that much.
@@ -9802,7 +10067,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// Comma acts as its right operand.
case BO_Comma:
- return GetExprRange(C, BO->getRHS(), MaxWidth);
+ return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext);
// Black-list pointer subtractions.
case BO_Sub:
@@ -9815,7 +10080,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
case BO_Div: {
// Don't 'pre-truncate' the operands.
unsigned opWidth = C.getIntWidth(GetExprType(E));
- IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+ IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext);
// If the divisor is constant, use that.
llvm::APSInt divisor;
@@ -9829,7 +10094,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
}
// Otherwise, just use the LHS's width.
- IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+ IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext);
return IntRange(L.Width, L.NonNegative && R.NonNegative);
}
@@ -9838,8 +10103,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
case BO_Rem: {
// Don't 'pre-truncate' the operands.
unsigned opWidth = C.getIntWidth(GetExprType(E));
- IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
- IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+ IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext);
+ IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext);
IntRange meet = IntRange::meet(L, R);
meet.Width = std::min(meet.Width, MaxWidth);
@@ -9856,8 +10121,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
// The default case is to treat the operation as if it were closed
// on the narrowest type that encompasses both operands.
- IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
- IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext);
+ IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext);
return IntRange::join(L, R);
}
@@ -9873,12 +10138,12 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
return IntRange::forValueOfType(C, GetExprType(E));
default:
- return GetExprRange(C, UO->getSubExpr(), MaxWidth);
+ return GetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext);
}
}
if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
- return GetExprRange(C, OVE->getSourceExpr(), MaxWidth);
+ return GetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext);
if (const auto *BitField = E->getSourceBitField())
return IntRange(BitField->getBitWidthValue(C),
@@ -9887,8 +10152,9 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
return IntRange::forValueOfType(C, GetExprType(E));
}
-static IntRange GetExprRange(ASTContext &C, const Expr *E) {
- return GetExprRange(C, E, C.getIntWidth(GetExprType(E)));
+static IntRange GetExprRange(ASTContext &C, const Expr *E,
+ bool InConstantContext) {
+ return GetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext);
}
/// Checks whether the given value, which currently has the given
@@ -9938,9 +10204,16 @@ static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
if (isa<EnumConstantDecl>(DR->getDecl()))
return true;
- // Suppress cases where the '0' value is expanded from a macro.
- if (E->getBeginLoc().isMacroID())
- return true;
+ // Suppress cases where the value is expanded from a macro, unless that macro
+ // is how a language represents a boolean literal. This is the case in both C
+ // and Objective-C.
+ SourceLocation BeginLoc = E->getBeginLoc();
+ if (BeginLoc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroName(
+ BeginLoc, S.getSourceManager(), S.getLangOpts());
+ return MacroName != "YES" && MacroName != "NO" &&
+ MacroName != "true" && MacroName != "false";
+ }
return false;
}
@@ -10132,11 +10405,17 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
OtherT = AT->getValueType();
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ // Special case for ObjC BOOL on targets where its a typedef for a signed char
+ // (Namely, macOS).
+ bool IsObjCSignedCharBool = S.getLangOpts().ObjC &&
+ S.NSAPIObj->isObjCBOOLType(OtherT) &&
+ OtherT->isSpecificBuiltinType(BuiltinType::SChar);
+
// Whether we're treating Other as being a bool because of the form of
// expression despite it having another type (typically 'int' in C).
bool OtherIsBooleanDespiteType =
!OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue();
- if (OtherIsBooleanDespiteType)
+ if (OtherIsBooleanDespiteType || IsObjCSignedCharBool)
OtherRange = IntRange::forBoolType();
// Determine the promoted range of the other type and see if a comparison of
@@ -10167,22 +10446,34 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
// Should be enough for uint128 (39 decimal digits)
SmallString<64> PrettySourceValue;
llvm::raw_svector_ostream OS(PrettySourceValue);
- if (ED)
+ if (ED) {
OS << '\'' << *ED << "' (" << Value << ")";
- else
+ } else if (auto *BL = dyn_cast<ObjCBoolLiteralExpr>(
+ Constant->IgnoreParenImpCasts())) {
+ OS << (BL->getValue() ? "YES" : "NO");
+ } else {
OS << Value;
+ }
+
+ if (IsObjCSignedCharBool) {
+ S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
+ S.PDiag(diag::warn_tautological_compare_objc_bool)
+ << OS.str() << *Result);
+ return true;
+ }
// FIXME: We use a somewhat different formatting for the in-range cases and
// cases involving boolean values for historical reasons. We should pick a
// consistent way of presenting these diagnostics.
if (!InRange || Other->isKnownToHaveBooleanValue()) {
+
S.DiagRuntimeBehavior(
- E->getOperatorLoc(), E,
- S.PDiag(!InRange ? diag::warn_out_of_range_compare
- : diag::warn_tautological_bool_compare)
- << OS.str() << classifyConstantValue(Constant)
- << OtherT << OtherIsBooleanDespiteType << *Result
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
+ E->getOperatorLoc(), E,
+ S.PDiag(!InRange ? diag::warn_out_of_range_compare
+ : diag::warn_tautological_bool_compare)
+ << OS.str() << classifyConstantValue(Constant) << OtherT
+ << OtherIsBooleanDespiteType << *Result
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
} else {
unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0)
? (HasEnumType(OriginalOther)
@@ -10286,7 +10577,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
}
// Otherwise, calculate the effective range of the signed operand.
- IntRange signedRange = GetExprRange(S.Context, signedOperand);
+ IntRange signedRange =
+ GetExprRange(S.Context, signedOperand, S.isConstantEvaluated());
// Go ahead and analyze implicit conversions in the operands. Note
// that we skip the implicit conversions on both sides.
@@ -10303,7 +10595,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// change the result of the comparison.
if (E->isEqualityOp()) {
unsigned comparisonWidth = S.Context.getIntWidth(T);
- IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand);
+ IntRange unsignedRange =
+ GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluated());
// We should never be unable to prove that the unsigned operand is
// non-negative.
@@ -10314,9 +10607,9 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
}
S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
- S.PDiag(diag::warn_mixed_sign_comparison)
- << LHS->getType() << RHS->getType()
- << LHS->getSourceRange() << RHS->getSourceRange());
+ S.PDiag(diag::warn_mixed_sign_comparison)
+ << LHS->getType() << RHS->getType()
+ << LHS->getSourceRange() << RHS->getSourceRange());
}
/// Analyzes an attempt to assign the given value to a bitfield.
@@ -10484,8 +10777,8 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
if (pruneControlFlow) {
S.DiagRuntimeBehavior(E->getExprLoc(), E,
S.PDiag(diag)
- << SourceType << T << E->getSourceRange()
- << SourceRange(CContext));
+ << SourceType << T << E->getSourceRange()
+ << SourceRange(CContext));
return;
}
S.Diag(E->getExprLoc(), diag)
@@ -10622,16 +10915,18 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
// The below checks assume source is floating point.
if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return;
- // If source is floating point but target is not.
+ // If source is floating point but target is an integer.
+ if (ResultBT->isInteger())
+ return DiagnoseImpCast(S, E, E->getRHS()->getType(), E->getLHS()->getType(),
+ E->getExprLoc(), diag::warn_impcast_float_integer);
+
if (!ResultBT->isFloatingPoint())
- return DiagnoseFloatingImpCast(S, E, E->getRHS()->getType(),
- E->getExprLoc());
-
- // If both source and target are floating points.
- // Builtin FP kinds are ordered by increasing FP rank.
- if (ResultBT->getKind() < RBT->getKind() &&
- // We don't want to warn for system macro.
- !S.SourceMgr.isInSystemMacro(E->getOperatorLoc()))
+ return;
+
+ // If both source and target are floating points, warn about losing precision.
+ int Order = S.getASTContext().getFloatingTypeSemanticOrder(
+ QualType(ResultBT, 0), QualType(RBT, 0));
+ if (Order < 0 && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc()))
// warn about dropping FP rank.
DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), E->getOperatorLoc(),
diag::warn_impcast_float_result_precision);
@@ -10856,6 +11151,11 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
return true;
}
+static bool isObjCSignedCharBool(Sema &S, QualType Ty) {
+ return Ty->isSpecificBuiltinType(BuiltinType::SChar) &&
+ S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
+}
+
static void
CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
bool *ICContext = nullptr) {
@@ -10899,6 +11199,29 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
}
}
+ // If the we're converting a constant to an ObjC BOOL on a platform where BOOL
+ // is a typedef for signed char (macOS), then that constant value has to be 1
+ // or 0.
+ if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsInt(Result, S.getASTContext(),
+ Expr::SE_AllowSideEffects) &&
+ Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
+ auto Builder = S.Diag(CC, diag::warn_impcast_constant_int_to_objc_bool)
+ << Result.Val.getInt().toString(10);
+ Expr *Ignored = E->IgnoreImplicit();
+ bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) ||
+ isa<BinaryOperator>(Ignored) ||
+ isa<CXXOperatorCallExpr>(Ignored);
+ SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc());
+ if (NeedsParens)
+ Builder << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO");
+ return;
+ }
+ }
+
// Check implicit casts from Objective-C collection literals to specialized
// collection types, e.g., NSArray<NSString *> *.
if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E))
@@ -10950,8 +11273,9 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
if (TargetBT && TargetBT->isFloatingPoint()) {
// ...then warn if we're dropping FP rank.
- // Builtin FP kinds are ordered by increasing FP rank.
- if (SourceBT->getKind() > TargetBT->getKind()) {
+ int Order = S.getASTContext().getFloatingTypeSemanticOrder(
+ QualType(SourceBT, 0), QualType(TargetBT, 0));
+ if (Order > 0) {
// Don't warn about float constants that are precisely
// representable in the target type.
Expr::EvalResult result;
@@ -10969,7 +11293,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision);
}
// ... or possibly if we're increasing rank, too
- else if (TargetBT->getKind() > SourceBT->getKind()) {
+ else if (Order < 0) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -11013,6 +11337,69 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
return;
}
+ // Valid casts involving fixed point types should be accounted for here.
+ if (Source->isFixedPointType()) {
+ if (Target->isUnsaturatedFixedPointType()) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects,
+ S.isConstantEvaluated())) {
+ APFixedPoint Value = Result.Val.getFixedPoint();
+ APFixedPoint MaxVal = S.Context.getFixedPointMax(T);
+ APFixedPoint MinVal = S.Context.getFixedPointMin(T);
+ if (Value > MaxVal || Value < MinVal) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_fixed_point_range)
+ << Value.toString() << T
+ << E->getSourceRange()
+ << clang::SourceRange(CC));
+ return;
+ }
+ }
+ } else if (Target->isIntegerType()) {
+ Expr::EvalResult Result;
+ if (!S.isConstantEvaluated() &&
+ E->EvaluateAsFixedPoint(Result, S.Context,
+ Expr::SE_AllowSideEffects)) {
+ APFixedPoint FXResult = Result.Val.getFixedPoint();
+
+ bool Overflowed;
+ llvm::APSInt IntResult = FXResult.convertToInt(
+ S.Context.getIntWidth(T),
+ Target->isSignedIntegerOrEnumerationType(), &Overflowed);
+
+ if (Overflowed) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_fixed_point_range)
+ << FXResult.toString() << T
+ << E->getSourceRange()
+ << clang::SourceRange(CC));
+ return;
+ }
+ }
+ }
+ } else if (Target->isUnsaturatedFixedPointType()) {
+ if (Source->isIntegerType()) {
+ Expr::EvalResult Result;
+ if (!S.isConstantEvaluated() &&
+ E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) {
+ llvm::APSInt Value = Result.Val.getInt();
+
+ bool Overflowed;
+ APFixedPoint IntResult = APFixedPoint::getFromIntValue(
+ Value, S.Context.getFixedPointSemantics(T), &Overflowed);
+
+ if (Overflowed) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_fixed_point_range)
+ << Value.toString(/*Radix=*/10) << T
+ << E->getSourceRange()
+ << clang::SourceRange(CC));
+ return;
+ }
+ }
+ }
+ }
+
DiagnoseNullConversion(S, E, T, CC);
S.DiscardMisalignedMemberAddress(Target, E);
@@ -11025,14 +11412,15 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
if (Target->isSpecificBuiltinType(BuiltinType::Bool))
return;
- IntRange SourceRange = GetExprRange(S.Context, E);
+ IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
if (SourceRange.Width > TargetRange.Width) {
// If the source is a constant, use a default-on diagnostic.
// TODO: this should happen for bitfield stores, too.
Expr::EvalResult Result;
- if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) {
+ if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects,
+ S.isConstantEvaluated())) {
llvm::APSInt Value(32);
Value = Result.Val.getInt();
@@ -11042,11 +11430,11 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation 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));
+ S.DiagRuntimeBehavior(
+ E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_integer_precision_constant)
+ << PrettySourceValue << PrettyTargetValue << E->getType() << T
+ << E->getSourceRange() << clang::SourceRange(CC));
return;
}
@@ -11464,6 +11852,9 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
}
if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+ // Skip function template not specialized yet.
+ if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return;
auto ParamIter = llvm::find(FD->parameters(), PV);
assert(ParamIter != FD->param_end());
unsigned ParamNo = std::distance(FD->param_begin(), ParamIter);
@@ -11641,12 +12032,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
class Seq {
friend class SequenceTree;
- unsigned Index = 0;
+ unsigned Index;
explicit Seq(unsigned N) : Index(N) {}
public:
- Seq() = default;
+ Seq() : Index(0) {}
};
SequenceTree() { Values.push_back(Value(0)); }
@@ -11710,19 +12101,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
};
struct Usage {
- Expr *Use = nullptr;
+ Expr *Use;
SequenceTree::Seq Seq;
- Usage() = default;
+ Usage() : Use(nullptr), Seq() {}
};
struct UsageInfo {
Usage Uses[UK_Count];
/// Have we issued a diagnostic for this variable already?
- bool Diagnosed = false;
+ bool Diagnosed;
- UsageInfo() = default;
+ UsageInfo() : Uses(), Diagnosed(false) {}
};
using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>;
@@ -11791,7 +12182,8 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
bool evaluate(const Expr *E, bool &Result) {
if (!EvalOK || E->isValueDependent())
return false;
- EvalOK = E->EvaluateAsBooleanCondition(Result, Self.SemaRef.Context);
+ EvalOK = E->EvaluateAsBooleanCondition(
+ Result, Self.SemaRef.Context, Self.SemaRef.isConstantEvaluated());
return EvalOK;
}
@@ -11849,10 +12241,11 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
if (OtherKind == UK_Use)
std::swap(Mod, ModOrUse);
- SemaRef.Diag(Mod->getExprLoc(),
- IsModMod ? diag::warn_unsequenced_mod_mod
- : diag::warn_unsequenced_mod_use)
- << O << SourceRange(ModOrUse->getExprLoc());
+ SemaRef.DiagRuntimeBehavior(
+ Mod->getExprLoc(), {Mod, ModOrUse},
+ SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod
+ : diag::warn_unsequenced_mod_use)
+ << O << SourceRange(ModOrUse->getExprLoc()));
UI.Diagnosed = true;
}
@@ -12143,6 +12536,8 @@ void Sema::CheckUnsequencedOperations(Expr *E) {
void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
bool IsConstexpr) {
+ llvm::SaveAndRestore<bool> ConstantContext(
+ isConstantEvaluatedOverride, IsConstexpr || isa<ConstantExpr>(E));
CheckImplicitConversions(E, CheckLoc);
if (!E->isInstantiationDependent())
CheckUnsequencedOperations(E);
@@ -12381,6 +12776,10 @@ static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size,
void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE,
bool AllowOnePastEnd, bool IndexNegated) {
+ // Already diagnosed by the constant evaluator.
+ if (isConstantEvaluated())
+ return;
+
IndexExpr = IndexExpr->IgnoreParenImpCasts();
if (IndexExpr->isValueDependent())
return;
@@ -12395,6 +12794,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
return;
const Type *BaseType = ArrayTy->getElementType().getTypePtr();
+ if (EffectiveType->isDependentType() || BaseType->isDependentType())
+ return;
Expr::EvalResult Result;
if (!IndexExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects))
@@ -13516,8 +13917,13 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
/// \param VD Declaration of an identifier that appears in a type tag.
///
/// \param MagicValue Type tag magic value.
+///
+/// \param isConstantEvaluated wether the evalaution should be performed in
+
+/// constant context.
static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
- const ValueDecl **VD, uint64_t *MagicValue) {
+ const ValueDecl **VD, uint64_t *MagicValue,
+ bool isConstantEvaluated) {
while(true) {
if (!TypeExpr)
return false;
@@ -13555,7 +13961,8 @@ static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
const AbstractConditionalOperator *ACO =
cast<AbstractConditionalOperator>(TypeExpr);
bool Result;
- if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx)) {
+ if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx,
+ isConstantEvaluated)) {
if (Result)
TypeExpr = ACO->getTrueExpr();
else
@@ -13591,14 +13998,17 @@ static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
///
/// \param TypeInfo Information about the corresponding C type.
///
+/// \param isConstantEvaluated wether the evalaution should be performed in
+/// constant context.
+///
/// \returns true if the corresponding C type was found.
static bool GetMatchingCType(
- const IdentifierInfo *ArgumentKind,
- const Expr *TypeExpr, const ASTContext &Ctx,
- const llvm::DenseMap<Sema::TypeTagMagicValue,
- Sema::TypeTagData> *MagicValues,
- bool &FoundWrongKind,
- Sema::TypeTagData &TypeInfo) {
+ const IdentifierInfo *ArgumentKind, const Expr *TypeExpr,
+ const ASTContext &Ctx,
+ const llvm::DenseMap<Sema::TypeTagMagicValue, Sema::TypeTagData>
+ *MagicValues,
+ bool &FoundWrongKind, Sema::TypeTagData &TypeInfo,
+ bool isConstantEvaluated) {
FoundWrongKind = false;
// Variable declaration that has type_tag_for_datatype attribute.
@@ -13606,7 +14016,7 @@ static bool GetMatchingCType(
uint64_t MagicValue;
- if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue))
+ if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue, isConstantEvaluated))
return false;
if (VD) {
@@ -13684,8 +14094,8 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
bool FoundWrongKind;
TypeTagData TypeInfo;
if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
- TypeTagForDatatypeMagicValues.get(),
- FoundWrongKind, TypeInfo)) {
+ TypeTagForDatatypeMagicValues.get(), FoundWrongKind,
+ TypeInfo, isConstantEvaluated())) {
if (FoundWrongKind)
Diag(TypeTagExpr->getExprLoc(),
diag::warn_type_tag_for_datatype_wrong_kind)
@@ -13787,8 +14197,7 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
if (isa<MemberExpr>(Op)) {
- auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(),
- MisalignedMember(Op));
+ auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));
if (MA != MisalignedMembers.end() &&
(T->isIntegerType() ||
(T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index d9f007a46da5..e4bbee86e350 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1,9 +1,8 @@
//===---------------- SemaCodeComplete.cpp - Code Completion ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -17,7 +16,9 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/QualTypeNames.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -38,6 +39,7 @@
#include "llvm/Support/Path.h"
#include <list>
#include <map>
+#include <string>
#include <vector>
using namespace clang;
@@ -82,6 +84,15 @@ private:
public:
ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) {}
+ ShadowMapEntry(const ShadowMapEntry &) = delete;
+ ShadowMapEntry(ShadowMapEntry &&Move) { *this = std::move(Move); }
+ ShadowMapEntry &operator=(const ShadowMapEntry &) = delete;
+ ShadowMapEntry &operator=(ShadowMapEntry &&Move) {
+ SingleDeclIndex = Move.SingleDeclIndex;
+ DeclOrVector = Move.DeclOrVector;
+ Move.DeclOrVector = nullptr;
+ return *this;
+ }
void Add(const NamedDecl *ND, unsigned Index) {
if (DeclOrVector.isNull()) {
@@ -105,7 +116,7 @@ private:
DeclIndexPair(ND, Index));
}
- void Destroy() {
+ ~ShadowMapEntry() {
if (DeclIndexPairVector *Vec =
DeclOrVector.dyn_cast<DeclIndexPairVector *>()) {
delete Vec;
@@ -152,9 +163,16 @@ private:
/// different levels of, e.g., the inheritance hierarchy.
std::list<ShadowMap> ShadowMaps;
+ /// Overloaded C++ member functions found by SemaLookup.
+ /// Used to determine when one overload is dominated by another.
+ llvm::DenseMap<std::pair<DeclContext *, /*Name*/uintptr_t>, ShadowMapEntry>
+ OverloadMap;
+
/// If we're potentially referring to a C++ member function, the set
/// of qualifiers applied to the object type.
Qualifiers ObjectTypeQualifiers;
+ /// The kind of the object expression, for rvalue/lvalue overloads.
+ ExprValueKind ObjectKind;
/// Whether the \p ObjectTypeQualifiers field is active.
bool HasObjectTypeQualifiers;
@@ -230,8 +248,9 @@ public:
/// out member functions that aren't available (because there will be a
/// cv-qualifier mismatch) or prefer functions with an exact qualifier
/// match.
- void setObjectTypeQualifiers(Qualifiers Quals) {
+ void setObjectTypeQualifiers(Qualifiers Quals, ExprValueKind Kind) {
ObjectTypeQualifiers = Quals;
+ ObjectKind = Kind;
HasObjectTypeQualifiers = true;
}
@@ -348,6 +367,202 @@ public:
};
} // namespace
+void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) {
+ if (isa<BlockDecl>(S.CurContext)) {
+ if (sema::BlockScopeInfo *BSI = S.getCurBlock()) {
+ ComputeType = nullptr;
+ Type = BSI->ReturnType;
+ ExpectedLoc = Tok;
+ }
+ } else if (const auto *Function = dyn_cast<FunctionDecl>(S.CurContext)) {
+ ComputeType = nullptr;
+ Type = Function->getReturnType();
+ ExpectedLoc = Tok;
+ } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(S.CurContext)) {
+ ComputeType = nullptr;
+ Type = Method->getReturnType();
+ ExpectedLoc = Tok;
+ }
+}
+
+void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) {
+ auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D);
+ ComputeType = nullptr;
+ Type = VD ? VD->getType() : QualType();
+ ExpectedLoc = Tok;
+}
+
+void PreferredTypeBuilder::enterFunctionArgument(
+ SourceLocation Tok, llvm::function_ref<QualType()> ComputeType) {
+ this->ComputeType = ComputeType;
+ Type = QualType();
+ ExpectedLoc = Tok;
+}
+
+void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok,
+ SourceLocation LParLoc) {
+ // expected type for parenthesized expression does not change.
+ if (ExpectedLoc == LParLoc)
+ ExpectedLoc = Tok;
+}
+
+static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS,
+ tok::TokenKind Op) {
+ if (!LHS)
+ return QualType();
+
+ QualType LHSType = LHS->getType();
+ if (LHSType->isPointerType()) {
+ if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal)
+ return S.getASTContext().getPointerDiffType();
+ // Pointer difference is more common than subtracting an int from a pointer.
+ if (Op == tok::minus)
+ return LHSType;
+ }
+
+ switch (Op) {
+ // No way to infer the type of RHS from LHS.
+ case tok::comma:
+ return QualType();
+ // Prefer the type of the left operand for all of these.
+ // Arithmetic operations.
+ case tok::plus:
+ case tok::plusequal:
+ case tok::minus:
+ case tok::minusequal:
+ case tok::percent:
+ case tok::percentequal:
+ case tok::slash:
+ case tok::slashequal:
+ case tok::star:
+ case tok::starequal:
+ // Assignment.
+ case tok::equal:
+ // Comparison operators.
+ case tok::equalequal:
+ case tok::exclaimequal:
+ case tok::less:
+ case tok::lessequal:
+ case tok::greater:
+ case tok::greaterequal:
+ case tok::spaceship:
+ return LHS->getType();
+ // Binary shifts are often overloaded, so don't try to guess those.
+ case tok::greatergreater:
+ case tok::greatergreaterequal:
+ case tok::lessless:
+ case tok::lesslessequal:
+ if (LHSType->isIntegralOrEnumerationType())
+ return S.getASTContext().IntTy;
+ return QualType();
+ // Logical operators, assume we want bool.
+ case tok::ampamp:
+ case tok::pipepipe:
+ case tok::caretcaret:
+ return S.getASTContext().BoolTy;
+ // Operators often used for bit manipulation are typically used with the type
+ // of the left argument.
+ case tok::pipe:
+ case tok::pipeequal:
+ case tok::caret:
+ case tok::caretequal:
+ case tok::amp:
+ case tok::ampequal:
+ if (LHSType->isIntegralOrEnumerationType())
+ return LHSType;
+ return QualType();
+ // RHS should be a pointer to a member of the 'LHS' type, but we can't give
+ // any particular type here.
+ case tok::periodstar:
+ case tok::arrowstar:
+ return QualType();
+ default:
+ // FIXME(ibiryukov): handle the missing op, re-add the assertion.
+ // assert(false && "unhandled binary op");
+ return QualType();
+ }
+}
+
+/// Get preferred type for an argument of an unary expression. \p ContextType is
+/// preferred type of the whole unary expression.
+static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType,
+ tok::TokenKind Op) {
+ switch (Op) {
+ case tok::exclaim:
+ return S.getASTContext().BoolTy;
+ case tok::amp:
+ if (!ContextType.isNull() && ContextType->isPointerType())
+ return ContextType->getPointeeType();
+ return QualType();
+ case tok::star:
+ if (ContextType.isNull())
+ return QualType();
+ return S.getASTContext().getPointerType(ContextType.getNonReferenceType());
+ case tok::plus:
+ case tok::minus:
+ case tok::tilde:
+ case tok::minusminus:
+ case tok::plusplus:
+ if (ContextType.isNull())
+ return S.getASTContext().IntTy;
+ // leave as is, these operators typically return the same type.
+ return ContextType;
+ case tok::kw___real:
+ case tok::kw___imag:
+ return QualType();
+ default:
+ assert(false && "unhandled unary op");
+ return QualType();
+ }
+}
+
+void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS,
+ tok::TokenKind Op) {
+ ComputeType = nullptr;
+ Type = getPreferredTypeOfBinaryRHS(S, LHS, Op);
+ ExpectedLoc = Tok;
+}
+
+void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok,
+ Expr *Base) {
+ if (!Base)
+ return;
+ // Do we have expected type for Base?
+ if (ExpectedLoc != Base->getBeginLoc())
+ return;
+ // Keep the expected type, only update the location.
+ ExpectedLoc = Tok;
+ return;
+}
+
+void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok,
+ tok::TokenKind OpKind,
+ SourceLocation OpLoc) {
+ ComputeType = nullptr;
+ Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind);
+ ExpectedLoc = Tok;
+}
+
+void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok,
+ Expr *LHS) {
+ ComputeType = nullptr;
+ Type = S.getASTContext().IntTy;
+ ExpectedLoc = Tok;
+}
+
+void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok,
+ QualType CastType) {
+ ComputeType = nullptr;
+ Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType();
+ ExpectedLoc = Tok;
+}
+
+void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) {
+ ComputeType = nullptr;
+ Type = S.getASTContext().BoolTy;
+ ExpectedLoc = Tok;
+}
+
class ResultBuilder::ShadowMapEntry::iterator {
llvm::PointerUnion<const NamedDecl *, const DeclIndexPair *> DeclOrIterator;
unsigned SingleDeclIndex;
@@ -681,7 +896,8 @@ QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) {
T = Property->getType();
else if (const auto *Value = dyn_cast<ValueDecl>(ND))
T = Value->getType();
- else
+
+ if (T.isNull())
return QualType();
// Dig through references, function pointers, and block pointers to
@@ -792,8 +1008,8 @@ void ResultBuilder::AdjustResultPriorityForDecl(Result &R) {
}
}
-DeclContext::lookup_result getConstructors(ASTContext &Context,
- const CXXRecordDecl *Record) {
+static DeclContext::lookup_result getConstructors(ASTContext &Context,
+ const CXXRecordDecl *Record) {
QualType RecordTy = Context.getTypeDeclType(Record);
DeclarationName ConstructorName =
Context.DeclarationNames.getCXXConstructorName(
@@ -960,6 +1176,53 @@ static void setInBaseClass(ResultBuilder::Result &R) {
R.InBaseClass = true;
}
+enum class OverloadCompare { BothViable, Dominates, Dominated };
+// Will Candidate ever be called on the object, when overloaded with Incumbent?
+// Returns Dominates if Candidate is always called, Dominated if Incumbent is
+// always called, BothViable if either may be called dependending on arguments.
+// Precondition: must actually be overloads!
+static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
+ const CXXMethodDecl &Incumbent,
+ const Qualifiers &ObjectQuals,
+ ExprValueKind ObjectKind) {
+ if (Candidate.isVariadic() != Incumbent.isVariadic() ||
+ Candidate.getNumParams() != Incumbent.getNumParams() ||
+ Candidate.getMinRequiredArguments() !=
+ Incumbent.getMinRequiredArguments())
+ return OverloadCompare::BothViable;
+ for (unsigned I = 0, E = Candidate.getNumParams(); I != E; ++I)
+ if (Candidate.parameters()[I]->getType().getCanonicalType() !=
+ Incumbent.parameters()[I]->getType().getCanonicalType())
+ return OverloadCompare::BothViable;
+ if (!llvm::empty(Candidate.specific_attrs<EnableIfAttr>()) ||
+ !llvm::empty(Incumbent.specific_attrs<EnableIfAttr>()))
+ return OverloadCompare::BothViable;
+ // At this point, we know calls can't pick one or the other based on
+ // arguments, so one of the two must win. (Or both fail, handled elsewhere).
+ RefQualifierKind CandidateRef = Candidate.getRefQualifier();
+ RefQualifierKind IncumbentRef = Incumbent.getRefQualifier();
+ if (CandidateRef != IncumbentRef) {
+ // If the object kind is LValue/RValue, there's one acceptable ref-qualifier
+ // and it can't be mixed with ref-unqualified overloads (in valid code).
+
+ // For xvalue objects, we prefer the rvalue overload even if we have to
+ // add qualifiers (which is rare, because const&& is rare).
+ if (ObjectKind == clang::VK_XValue)
+ return CandidateRef == RQ_RValue ? OverloadCompare::Dominates
+ : OverloadCompare::Dominated;
+ }
+ // Now the ref qualifiers are the same (or we're in some invalid state).
+ // So make some decision based on the qualifiers.
+ Qualifiers CandidateQual = Candidate.getMethodQualifiers();
+ Qualifiers IncumbentQual = Incumbent.getMethodQualifiers();
+ bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual);
+ bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual);
+ if (CandidateSuperset == IncumbentSuperset)
+ return OverloadCompare::BothViable;
+ return IncumbentSuperset ? OverloadCompare::Dominates
+ : OverloadCompare::Dominated;
+}
+
void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
NamedDecl *Hiding, bool InBaseClass = false) {
if (R.Kind != Result::RK_Declaration) {
@@ -1028,7 +1291,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
if (HasObjectTypeQualifiers)
if (const auto *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
if (Method->isInstance()) {
- Qualifiers MethodQuals = Method->getTypeQualifiers();
+ Qualifiers MethodQuals = Method->getMethodQualifiers();
if (ObjectTypeQualifiers == MethodQuals)
R.Priority += CCD_ObjectQualifierMatch;
else if (ObjectTypeQualifiers - MethodQuals) {
@@ -1036,6 +1299,44 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
// qualifiers.
return;
}
+ // Detect cases where a ref-qualified method cannot be invoked.
+ switch (Method->getRefQualifier()) {
+ case RQ_LValue:
+ if (ObjectKind != VK_LValue && !MethodQuals.hasConst())
+ return;
+ break;
+ case RQ_RValue:
+ if (ObjectKind == VK_LValue)
+ return;
+ break;
+ case RQ_None:
+ break;
+ }
+
+ /// Check whether this dominates another overloaded method, which should
+ /// be suppressed (or vice versa).
+ /// Motivating case is const_iterator begin() const vs iterator begin().
+ auto &OverloadSet = OverloadMap[std::make_pair(
+ CurContext, Method->getDeclName().getAsOpaqueInteger())];
+ for (const DeclIndexPair& Entry : OverloadSet) {
+ Result &Incumbent = Results[Entry.second];
+ switch (compareOverloads(*Method,
+ *cast<CXXMethodDecl>(Incumbent.Declaration),
+ ObjectTypeQualifiers, ObjectKind)) {
+ case OverloadCompare::Dominates:
+ // Replace the dominated overload with this one.
+ // FIXME: if the overload dominates multiple incumbents then we
+ // should remove all. But two overloads is by far the common case.
+ Incumbent = std::move(R);
+ return;
+ case OverloadCompare::Dominated:
+ // This overload can't be called, drop it.
+ return;
+ case OverloadCompare::BothViable:
+ break;
+ }
+ }
+ OverloadSet.Add(Method, Results.size());
}
// Insert this result into the set of results.
@@ -1056,11 +1357,6 @@ void ResultBuilder::EnterNewScope() { ShadowMaps.emplace_back(); }
/// Exit from the current scope.
void ResultBuilder::ExitScope() {
- for (ShadowMap::iterator E = ShadowMaps.back().begin(),
- EEnd = ShadowMaps.back().end();
- E != EEnd; ++E)
- E->second.Destroy();
-
ShadowMaps.pop_back();
}
@@ -1516,6 +1812,7 @@ static void AddTypedefResult(ResultBuilder &Results) {
Builder.AddPlaceholderChunk("type");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("name");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
@@ -1629,22 +1926,10 @@ static void AddStaticAssertResult(CodeCompletionBuilder &Builder,
Builder.AddChunk(CodeCompletionString::CK_Comma);
Builder.AddPlaceholderChunk("message");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
-static void printOverrideString(llvm::raw_ostream &OS,
- CodeCompletionString *CCS) {
- for (const auto &C : *CCS) {
- if (C.Kind == CodeCompletionString::CK_Optional)
- printOverrideString(OS, C.Optional);
- else
- OS << C.Text;
- // Add a space after return type.
- if (C.Kind == CodeCompletionString::CK_ResultType)
- OS << ' ';
- }
-}
-
static void AddOverrideResults(ResultBuilder &Results,
const CodeCompletionContext &CCContext,
CodeCompletionBuilder &Builder) {
@@ -1714,7 +1999,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder.AddTypedTextChunk("namespace");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("identifier");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("declarations");
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
@@ -1727,14 +2014,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder.AddPlaceholderChunk("name");
Builder.AddChunk(CodeCompletionString::CK_Equal);
Builder.AddPlaceholderChunk("namespace");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
// Using directives
- Builder.AddTypedTextChunk("using");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddTextChunk("namespace");
+ Builder.AddTypedTextChunk("using namespace");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("identifier");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
// asm(string-literal)
@@ -1769,17 +2056,17 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder.AddPlaceholderChunk("qualifier");
Builder.AddTextChunk("::");
Builder.AddPlaceholderChunk("name");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
// using typename qualifier::name (only in a dependent context)
if (SemaRef.CurContext->isDependentContext()) {
- Builder.AddTypedTextChunk("using");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddTextChunk("typename");
+ Builder.AddTypedTextChunk("using typename");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("qualifier");
Builder.AddTextChunk("::");
Builder.AddPlaceholderChunk("name");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
}
@@ -1857,15 +2144,21 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns() &&
SemaRef.getLangOpts().CXXExceptions) {
Builder.AddTypedTextChunk("try");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("statements");
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddTextChunk("catch");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("declaration");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("statements");
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
@@ -1877,13 +2170,16 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
if (Results.includeCodePatterns()) {
// if (condition) { statements }
Builder.AddTypedTextChunk("if");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
if (SemaRef.getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("statements");
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
@@ -1891,14 +2187,18 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
// switch (condition) { }
Builder.AddTypedTextChunk("switch");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
if (SemaRef.getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddPlaceholderChunk("cases");
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
Results.AddResult(Result(Builder.TakeString()));
}
@@ -1922,13 +2222,16 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
if (Results.includeCodePatterns()) {
/// while (condition) { statements }
Builder.AddTypedTextChunk("while");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
if (SemaRef.getLangOpts().CPlusPlus)
Builder.AddPlaceholderChunk("condition");
else
Builder.AddPlaceholderChunk("expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("statements");
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
@@ -1936,11 +2239,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
// do { statements } while ( expression );
Builder.AddTypedTextChunk("do");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("statements");
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddChunk(CodeCompletionString::CK_RightBrace);
Builder.AddTextChunk("while");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -1948,16 +2254,20 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
// for ( for-init-statement ; condition ; expression ) { statements }
Builder.AddTypedTextChunk("for");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
if (SemaRef.getLangOpts().CPlusPlus || SemaRef.getLangOpts().C99)
Builder.AddPlaceholderChunk("init-statement");
else
Builder.AddPlaceholderChunk("init-expression");
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("condition");
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("inc-expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
Builder.AddPlaceholderChunk("statements");
@@ -1969,44 +2279,62 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
if (S->getContinueParent()) {
// continue ;
Builder.AddTypedTextChunk("continue");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
}
if (S->getBreakParent()) {
// break ;
Builder.AddTypedTextChunk("break");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
}
- // "return expression ;" or "return ;", depending on whether we
- // know the function is void or not.
- bool isVoid = false;
+ // "return expression ;" or "return ;", depending on the return type.
+ QualType ReturnType;
if (const auto *Function = dyn_cast<FunctionDecl>(SemaRef.CurContext))
- isVoid = Function->getReturnType()->isVoidType();
+ ReturnType = Function->getReturnType();
else if (const auto *Method = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))
- isVoid = Method->getReturnType()->isVoidType();
+ ReturnType = Method->getReturnType();
else if (SemaRef.getCurBlock() &&
!SemaRef.getCurBlock()->ReturnType.isNull())
- isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType();
- Builder.AddTypedTextChunk("return");
- if (!isVoid) {
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ ReturnType = SemaRef.getCurBlock()->ReturnType;;
+ if (ReturnType.isNull() || ReturnType->isVoidType()) {
+ Builder.AddTypedTextChunk("return");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Builder.TakeString()));
+ } else {
+ assert(!ReturnType.isNull());
+ // "return expression ;"
+ Builder.AddTypedTextChunk("return");
+ Builder.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Builder.TakeString()));
+ // When boolean, also add 'return true;' and 'return false;'.
+ if (ReturnType->isBooleanType()) {
+ Builder.AddTypedTextChunk("return true");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Builder.TakeString()));
+
+ Builder.AddTypedTextChunk("return false");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
- Results.AddResult(Result(Builder.TakeString()));
// goto identifier ;
Builder.AddTypedTextChunk("goto");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("label");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
// Using directives
- Builder.AddTypedTextChunk("using");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddTextChunk("namespace");
+ Builder.AddTypedTextChunk("using namespace");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("identifier");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
@@ -2409,6 +2737,11 @@ static std::string
FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
bool SuppressName = false, bool SuppressBlock = false,
Optional<ArrayRef<QualType>> ObjCSubsts = None) {
+ // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.
+ // It would be better to pass in the param Type, which is usually avaliable.
+ // But this case is rare, so just pretend we fell back to int as elsewhere.
+ if (!Param)
+ return "int";
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@@ -2736,23 +3069,23 @@ static void
AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
const FunctionDecl *Function) {
const auto *Proto = Function->getType()->getAs<FunctionProtoType>();
- if (!Proto || !Proto->getTypeQuals())
+ if (!Proto || !Proto->getMethodQuals())
return;
// FIXME: Add ref-qualifier!
// Handle single qualifiers without copying
- if (Proto->getTypeQuals().hasOnlyConst()) {
+ if (Proto->getMethodQuals().hasOnlyConst()) {
Result.AddInformativeChunk(" const");
return;
}
- if (Proto->getTypeQuals().hasOnlyVolatile()) {
+ if (Proto->getMethodQuals().hasOnlyVolatile()) {
Result.AddInformativeChunk(" volatile");
return;
}
- if (Proto->getTypeQuals().hasOnlyRestrict()) {
+ if (Proto->getMethodQuals().hasOnlyRestrict()) {
Result.AddInformativeChunk(" restrict");
return;
}
@@ -2952,19 +3285,42 @@ CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(
PP, Ctx, Result, IncludeBriefComments, CCContext, Policy);
}
+static void printOverrideString(const CodeCompletionString &CCS,
+ std::string &BeforeName,
+ std::string &NameAndSignature) {
+ bool SeenTypedChunk = false;
+ for (auto &Chunk : CCS) {
+ if (Chunk.Kind == CodeCompletionString::CK_Optional) {
+ assert(SeenTypedChunk && "optional parameter before name");
+ // Note that we put all chunks inside into NameAndSignature.
+ printOverrideString(*Chunk.Optional, NameAndSignature, NameAndSignature);
+ continue;
+ }
+ SeenTypedChunk |= Chunk.Kind == CodeCompletionString::CK_TypedText;
+ if (SeenTypedChunk)
+ NameAndSignature += Chunk.Text;
+ else
+ BeforeName += Chunk.Text;
+ }
+}
+
CodeCompletionString *
CodeCompletionResult::createCodeCompletionStringForOverride(
Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
bool IncludeBriefComments, const CodeCompletionContext &CCContext,
PrintingPolicy &Policy) {
- std::string OverrideSignature;
- llvm::raw_string_ostream OS(OverrideSignature);
auto *CCS = createCodeCompletionStringForDecl(PP, Ctx, Result,
/*IncludeBriefComments=*/false,
CCContext, Policy);
- printOverrideString(OS, CCS);
- OS << " override";
- Result.AddTypedTextChunk(Result.getAllocator().CopyString(OS.str()));
+ std::string BeforeName;
+ std::string NameAndSignature;
+ // For overrides all chunks go into the result, none are informative.
+ printOverrideString(*CCS, BeforeName, NameAndSignature);
+ NameAndSignature += " override";
+
+ Result.AddTextChunk(Result.getAllocator().CopyString(BeforeName));
+ Result.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Result.AddTypedTextChunk(Result.getAllocator().CopyString(NameAndSignature));
return Result.TakeString();
}
@@ -3740,7 +4096,8 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
// the member function to filter/prioritize the results list.
auto ThisType = getCurrentThisType();
if (!ThisType.isNull())
- Results.setObjectTypeQualifiers(ThisType->getPointeeType().getQualifiers());
+ Results.setObjectTypeQualifiers(ThisType->getPointeeType().getQualifiers(),
+ VK_LValue);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
@@ -3856,16 +4213,116 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
}
struct Sema::CodeCompleteExpressionData {
- CodeCompleteExpressionData(QualType PreferredType = QualType())
+ CodeCompleteExpressionData(QualType PreferredType = QualType(),
+ bool IsParenthesized = false)
: PreferredType(PreferredType), IntegralConstantExpression(false),
- ObjCCollection(false) {}
+ ObjCCollection(false), IsParenthesized(IsParenthesized) {}
QualType PreferredType;
bool IntegralConstantExpression;
bool ObjCCollection;
+ bool IsParenthesized;
SmallVector<Decl *, 4> IgnoreDecls;
};
+namespace {
+/// Information that allows to avoid completing redundant enumerators.
+struct CoveredEnumerators {
+ llvm::SmallPtrSet<EnumConstantDecl *, 8> Seen;
+ NestedNameSpecifier *SuggestedQualifier = nullptr;
+};
+} // namespace
+
+static void AddEnumerators(ResultBuilder &Results, ASTContext &Context,
+ EnumDecl *Enum, DeclContext *CurContext,
+ const CoveredEnumerators &Enumerators) {
+ NestedNameSpecifier *Qualifier = Enumerators.SuggestedQualifier;
+ if (Context.getLangOpts().CPlusPlus && !Qualifier && Enumerators.Seen.empty()) {
+ // If there are no prior enumerators in C++, check whether we have to
+ // qualify the names of the enumerators that we suggest, because they
+ // may not be visible in this scope.
+ Qualifier = getRequiredQualification(Context, CurContext, Enum);
+ }
+
+ Results.EnterNewScope();
+ for (auto *E : Enum->enumerators()) {
+ if (Enumerators.Seen.count(E))
+ continue;
+
+ CodeCompletionResult R(E, CCP_EnumInCase, Qualifier);
+ Results.AddResult(R, CurContext, nullptr, false);
+ }
+ Results.ExitScope();
+}
+
+/// Try to find a corresponding FunctionProtoType for function-like types (e.g.
+/// function pointers, std::function, etc).
+static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {
+ assert(!T.isNull());
+ // Try to extract first template argument from std::function<> and similar.
+ // Note we only handle the sugared types, they closely match what users wrote.
+ // We explicitly choose to not handle ClassTemplateSpecializationDecl.
+ if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {
+ if (Specialization->getNumArgs() != 1)
+ return nullptr;
+ const TemplateArgument &Argument = Specialization->getArg(0);
+ if (Argument.getKind() != TemplateArgument::Type)
+ return nullptr;
+ return Argument.getAsType()->getAs<FunctionProtoType>();
+ }
+ // Handle other cases.
+ if (T->isPointerType())
+ T = T->getPointeeType();
+ return T->getAs<FunctionProtoType>();
+}
+
+/// Adds a pattern completion for a lambda expression with the specified
+/// parameter types and placeholders for parameter names.
+static void AddLambdaCompletion(ResultBuilder &Results,
+ llvm::ArrayRef<QualType> Parameters,
+ const LangOptions &LangOpts) {
+ if (!Results.includeCodePatterns())
+ return;
+ CodeCompletionBuilder Completion(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
+ // [](<parameters>) {}
+ Completion.AddChunk(CodeCompletionString::CK_LeftBracket);
+ Completion.AddPlaceholderChunk("=");
+ Completion.AddChunk(CodeCompletionString::CK_RightBracket);
+ if (!Parameters.empty()) {
+ Completion.AddChunk(CodeCompletionString::CK_LeftParen);
+ bool First = true;
+ for (auto Parameter : Parameters) {
+ if (!First)
+ Completion.AddChunk(CodeCompletionString::ChunkKind::CK_Comma);
+ else
+ First = false;
+
+ constexpr llvm::StringLiteral NamePlaceholder = "!#!NAME_GOES_HERE!#!";
+ std::string Type = NamePlaceholder;
+ Parameter.getAsStringInternal(Type, PrintingPolicy(LangOpts));
+ llvm::StringRef Prefix, Suffix;
+ std::tie(Prefix, Suffix) = llvm::StringRef(Type).split(NamePlaceholder);
+ Prefix = Prefix.rtrim();
+ Suffix = Suffix.ltrim();
+
+ Completion.AddTextChunk(Completion.getAllocator().CopyString(Prefix));
+ Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Completion.AddPlaceholderChunk("parameter");
+ Completion.AddTextChunk(Completion.getAllocator().CopyString(Suffix));
+ };
+ Completion.AddChunk(CodeCompletionString::CK_RightParen);
+ }
+ Completion.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace);
+ Completion.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Completion.AddPlaceholderChunk("body");
+ Completion.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Completion.AddChunk(CodeCompletionString::CK_RightBrace);
+
+ Results.AddResult(Completion.TakeString());
+}
+
/// Perform code-completion in an expression context when we know what
/// type we're looking for.
void Sema::CodeCompleteExpression(Scope *S,
@@ -3873,13 +4330,18 @@ void Sema::CodeCompleteExpression(Scope *S,
ResultBuilder Results(
*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
- CodeCompletionContext(CodeCompletionContext::CCC_Expression,
- Data.PreferredType));
+ CodeCompletionContext(
+ Data.IsParenthesized
+ ? CodeCompletionContext::CCC_ParenthesizedExpression
+ : CodeCompletionContext::CCC_Expression,
+ Data.PreferredType));
+ auto PCC =
+ Data.IsParenthesized ? PCC_ParenthesizedExpression : PCC_Expression;
if (Data.ObjCCollection)
Results.setFilter(&ResultBuilder::IsObjCCollection);
else if (Data.IntegralConstantExpression)
Results.setFilter(&ResultBuilder::IsIntegralConstantValue);
- else if (WantTypesInContext(PCC_Expression, getLangOpts()))
+ else if (WantTypesInContext(PCC, getLangOpts()))
Results.setFilter(&ResultBuilder::IsOrdinaryName);
else
Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);
@@ -3897,14 +4359,23 @@ void Sema::CodeCompleteExpression(Scope *S,
CodeCompleter->loadExternal());
Results.EnterNewScope();
- AddOrdinaryNameResults(PCC_Expression, S, *this, Results);
+ AddOrdinaryNameResults(PCC, S, *this, Results);
Results.ExitScope();
bool PreferredTypeIsPointer = false;
- if (!Data.PreferredType.isNull())
+ if (!Data.PreferredType.isNull()) {
PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() ||
Data.PreferredType->isMemberPointerType() ||
Data.PreferredType->isBlockPointerType();
+ if (Data.PreferredType->isEnumeralType()) {
+ EnumDecl *Enum = Data.PreferredType->castAs<EnumType>()->getDecl();
+ if (auto *Def = Enum->getDefinition())
+ Enum = Def;
+ // FIXME: collect covered enumerators in cases like:
+ // if (x == my_enum::one) { ... } else if (x == ^) {}
+ AddEnumerators(Results, Context, Enum, CurContext, CoveredEnumerators());
+ }
+ }
if (S->getFnParent() && !Data.ObjCCollection &&
!Data.IntegralConstantExpression)
@@ -3913,17 +4384,28 @@ void Sema::CodeCompleteExpression(Scope *S,
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false,
PreferredTypeIsPointer);
+
+ // Complete a lambda expression when preferred type is a function.
+ if (!Data.PreferredType.isNull() && getLangOpts().CPlusPlus11) {
+ if (const FunctionProtoType *F =
+ TryDeconstructFunctionLike(Data.PreferredType))
+ AddLambdaCompletion(Results, F->getParamTypes(), getLangOpts());
+ }
+
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
Results.data(), Results.size());
}
-void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType) {
- return CodeCompleteExpression(S, CodeCompleteExpressionData(PreferredType));
+void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType,
+ bool IsParenthesized) {
+ return CodeCompleteExpression(
+ S, CodeCompleteExpressionData(PreferredType, IsParenthesized));
}
-void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
+void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E,
+ QualType PreferredType) {
if (E.isInvalid())
- CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction);
+ CodeCompleteExpression(S, PreferredType);
else if (getLangOpts().ObjC)
CodeCompleteObjCInstanceMessage(S, E.get(), None, false);
}
@@ -4169,13 +4651,12 @@ AddObjCProperties(const CodeCompletionContext &CCContext,
}
}
-static void
-AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
- Scope *S, QualType BaseType, RecordDecl *RD,
- Optional<FixItHint> AccessOpFixIt) {
+static void AddRecordMembersCompletionResults(
+ Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType,
+ ExprValueKind BaseKind, RecordDecl *RD, Optional<FixItHint> AccessOpFixIt) {
// Indicate that we are performing a member access, and the cv-qualifiers
// for the base object type.
- Results.setObjectTypeQualifiers(BaseType.getQualifiers());
+ Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind);
// Access to a C/C++ class, struct, or union.
Results.allowNestedNameSpecifiers();
@@ -4211,7 +4692,8 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Expr *OtherOpBase,
SourceLocation OpLoc, bool IsArrow,
- bool IsBaseExprStatement) {
+ bool IsBaseExprStatement,
+ QualType PreferredType) {
if (!Base || !CodeCompleter)
return;
@@ -4239,6 +4721,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
}
CodeCompletionContext CCContext(contextKind, ConvertedBaseType);
+ CCContext.setPreferredType(PreferredType);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(), CCContext,
&ResultBuilder::IsMember);
@@ -4254,18 +4737,20 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Base = ConvertedBase.get();
QualType BaseType = Base->getType();
+ ExprValueKind BaseKind = Base->getValueKind();
if (IsArrow) {
- if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
BaseType = Ptr->getPointeeType();
- else if (BaseType->isObjCObjectPointerType())
+ BaseKind = VK_LValue;
+ } else if (BaseType->isObjCObjectPointerType())
/*Do nothing*/;
else
return false;
}
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
- AddRecordMembersCompletionResults(*this, Results, S, BaseType,
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind,
Record->getDecl(),
std::move(AccessOpFixIt));
} else if (const auto *TST =
@@ -4274,13 +4759,13 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
if (const auto *TD =
dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) {
CXXRecordDecl *RD = TD->getTemplatedDecl();
- AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD,
- std::move(AccessOpFixIt));
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind,
+ RD, std::move(AccessOpFixIt));
}
} else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) {
if (auto *RD = ICNT->getDecl())
- AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD,
- std::move(AccessOpFixIt));
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind,
+ RD, std::move(AccessOpFixIt));
} else if (!IsArrow && BaseType->isObjCObjectPointerType()) {
// Objective-C property reference.
AddedPropertiesSet AddedProperties;
@@ -4497,8 +4982,7 @@ void Sema::CodeCompleteCase(Scope *S) {
// FIXME: Ideally, we would also be able to look *past* the code-completion
// token, in case we are code-completing in the middle of the switch and not
// at the end. However, we aren't able to do so at the moment.
- llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen;
- NestedNameSpecifier *Qualifier = nullptr;
+ CoveredEnumerators Enumerators;
for (SwitchCase *SC = Switch->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
CaseStmt *Case = dyn_cast<CaseStmt>(SC);
@@ -4515,7 +4999,7 @@ void Sema::CodeCompleteCase(Scope *S) {
// values of each enumerator. However, value-based approach would not
// work as well with C++ templates where enumerators declared within a
// template are type- and value-dependent.
- EnumeratorsSeen.insert(Enumerator);
+ Enumerators.Seen.insert(Enumerator);
// If this is a qualified-id, keep track of the nested-name-specifier
// so that we can reproduce it as part of code completion, e.g.,
@@ -4528,30 +5012,15 @@ void Sema::CodeCompleteCase(Scope *S) {
// At the XXX, our completions are TagDecl::TK_union,
// TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union,
// TK_struct, and TK_class.
- Qualifier = DRE->getQualifier();
+ Enumerators.SuggestedQualifier = DRE->getQualifier();
}
}
- if (getLangOpts().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) {
- // If there are no prior enumerators in C++, check whether we have to
- // qualify the names of the enumerators that we suggest, because they
- // may not be visible in this scope.
- Qualifier = getRequiredQualification(Context, CurContext, Enum);
- }
-
// Add any enumerators that have not yet been mentioned.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Expression);
- Results.EnterNewScope();
- for (auto *E : Enum->enumerators()) {
- if (EnumeratorsSeen.count(E))
- continue;
-
- CodeCompletionResult R(E, CCP_EnumInCase, Qualifier);
- Results.AddResult(R, CurContext, nullptr, false);
- }
- Results.ExitScope();
+ AddEnumerators(Results, Context, Enum, CurContext, Enumerators);
if (CodeCompleter->includeMacros()) {
AddMacroResults(PP, Results, CodeCompleter->loadExternal(), false);
@@ -4576,22 +5045,19 @@ typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
static void mergeCandidatesWithResults(
Sema &SemaRef, SmallVectorImpl<ResultCandidate> &Results,
OverloadCandidateSet &CandidateSet, SourceLocation Loc) {
- if (!CandidateSet.empty()) {
- // Sort the overload candidate set by placing the best overloads first.
- std::stable_sort(
- CandidateSet.begin(), CandidateSet.end(),
- [&](const OverloadCandidate &X, const OverloadCandidate &Y) {
- return isBetterOverloadCandidate(SemaRef, X, Y, Loc,
- CandidateSet.getKind());
- });
-
- // Add the remaining viable overload candidates as code-completion results.
- for (OverloadCandidate &Candidate : CandidateSet) {
- if (Candidate.Function && Candidate.Function->isDeleted())
- continue;
- if (Candidate.Viable)
- Results.push_back(ResultCandidate(Candidate.Function));
- }
+ // Sort the overload candidate set by placing the best overloads first.
+ llvm::stable_sort(CandidateSet, [&](const OverloadCandidate &X,
+ const OverloadCandidate &Y) {
+ return isBetterOverloadCandidate(SemaRef, X, Y, Loc,
+ CandidateSet.getKind());
+ });
+
+ // Add the remaining viable overload candidates as code-completion results.
+ for (OverloadCandidate &Candidate : CandidateSet) {
+ if (Candidate.Function && Candidate.Function->isDeleted())
+ continue;
+ if (Candidate.Viable)
+ Results.push_back(ResultCandidate(Candidate.Function));
}
}
@@ -4670,7 +5136,7 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
Decls.append(UME->decls_begin(), UME->decls_end());
const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase();
AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,
- /*SuppressUsedConversions=*/false,
+ /*SuppressUserConversions=*/false,
/*PartialOverloading=*/true, FirstArgumentIsBase);
} else {
FunctionDecl *FD = nullptr;
@@ -4685,7 +5151,7 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
else
AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()),
Args, CandidateSet,
- /*SuppressUsedConversions=*/false,
+ /*SuppressUserConversions=*/false,
/*PartialOverloading=*/true);
} else if (auto DC = NakedFn->getType()->getAsCXXRecordDecl()) {
@@ -4702,7 +5168,7 @@ QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
ArgExprs.append(Args.begin(), Args.end());
AddFunctionCandidates(R.asUnresolvedSet(), ArgExprs, CandidateSet,
/*ExplicitArgs=*/nullptr,
- /*SuppressUsedConversions=*/false,
+ /*SuppressUserConversions=*/false,
/*PartialOverloading=*/true);
}
} else {
@@ -4750,13 +5216,14 @@ QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
if (auto *FD = dyn_cast<FunctionDecl>(C)) {
AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
CandidateSet,
- /*SuppressUsedConversions=*/false,
- /*PartialOverloading=*/true);
+ /*SuppressUserConversions=*/false,
+ /*PartialOverloading=*/true,
+ /*AllowExplicit*/ true);
} else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
AddTemplateOverloadCandidate(
FTD, DeclAccessPair::make(FTD, C->getAccess()),
/*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
- /*SuppressUsedConversions=*/false,
+ /*SuppressUserConversions=*/false,
/*PartialOverloading=*/true);
}
}
@@ -4800,22 +5267,6 @@ void Sema::CodeCompleteInitializer(Scope *S, Decl *D) {
CodeCompleteExpression(S, Data);
}
-void Sema::CodeCompleteReturn(Scope *S) {
- QualType ResultType;
- if (isa<BlockDecl>(CurContext)) {
- if (BlockScopeInfo *BSI = getCurBlock())
- ResultType = BSI->ReturnType;
- } else if (const auto *Function = dyn_cast<FunctionDecl>(CurContext))
- ResultType = Function->getReturnType();
- else if (const auto *Method = dyn_cast<ObjCMethodDecl>(CurContext))
- ResultType = Method->getReturnType();
-
- if (ResultType.isNull())
- CodeCompleteOrdinaryName(S, PCC_Expression);
- else
- CodeCompleteExpression(S, ResultType);
-}
-
void Sema::CodeCompleteAfterIf(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
@@ -4845,9 +5296,7 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
Results.AddResult(Builder.TakeString());
// "else if" block
- Builder.AddTypedTextChunk("else");
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddTextChunk("if");
+ Builder.AddTypedTextChunk("else if");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
if (getLangOpts().CPlusPlus)
@@ -4877,93 +5326,9 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
Results.data(), Results.size());
}
-static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS,
- tok::TokenKind Op) {
- if (!LHS)
- return QualType();
-
- QualType LHSType = LHS->getType();
- if (LHSType->isPointerType()) {
- if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal)
- return S.getASTContext().getPointerDiffType();
- // Pointer difference is more common than subtracting an int from a pointer.
- if (Op == tok::minus)
- return LHSType;
- }
-
- switch (Op) {
- // No way to infer the type of RHS from LHS.
- case tok::comma:
- return QualType();
- // Prefer the type of the left operand for all of these.
- // Arithmetic operations.
- case tok::plus:
- case tok::plusequal:
- case tok::minus:
- case tok::minusequal:
- case tok::percent:
- case tok::percentequal:
- case tok::slash:
- case tok::slashequal:
- case tok::star:
- case tok::starequal:
- // Assignment.
- case tok::equal:
- // Comparison operators.
- case tok::equalequal:
- case tok::exclaimequal:
- case tok::less:
- case tok::lessequal:
- case tok::greater:
- case tok::greaterequal:
- case tok::spaceship:
- return LHS->getType();
- // Binary shifts are often overloaded, so don't try to guess those.
- case tok::greatergreater:
- case tok::greatergreaterequal:
- case tok::lessless:
- case tok::lesslessequal:
- if (LHSType->isIntegralOrEnumerationType())
- return S.getASTContext().IntTy;
- return QualType();
- // Logical operators, assume we want bool.
- case tok::ampamp:
- case tok::pipepipe:
- case tok::caretcaret:
- return S.getASTContext().BoolTy;
- // Operators often used for bit manipulation are typically used with the type
- // of the left argument.
- case tok::pipe:
- case tok::pipeequal:
- case tok::caret:
- case tok::caretequal:
- case tok::amp:
- case tok::ampequal:
- if (LHSType->isIntegralOrEnumerationType())
- return LHSType;
- return QualType();
- // RHS should be a pointer to a member of the 'LHS' type, but we can't give
- // any particular type here.
- case tok::periodstar:
- case tok::arrowstar:
- return QualType();
- default:
- // FIXME(ibiryukov): handle the missing op, re-add the assertion.
- // assert(false && "unhandled binary op");
- return QualType();
- }
-}
-
-void Sema::CodeCompleteBinaryRHS(Scope *S, Expr *LHS, tok::TokenKind Op) {
- auto PreferredType = getPreferredTypeOfBinaryRHS(*this, LHS, Op);
- if (!PreferredType.isNull())
- CodeCompleteExpression(S, PreferredType);
- else
- CodeCompleteOrdinaryName(S, PCC_Expression);
-}
-
void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
- bool EnteringContext, QualType BaseType) {
+ bool EnteringContext, QualType BaseType,
+ QualType PreferredType) {
if (SS.isEmpty() || !CodeCompleter)
return;
@@ -4972,9 +5337,24 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
// it can be useful for global code completion which have information about
// contexts/symbols that are not in the AST.
if (SS.isInvalid()) {
- CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol);
+ CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType);
CC.setCXXScopeSpecifier(SS);
- HandleCodeCompleteResults(this, CodeCompleter, CC, nullptr, 0);
+ // As SS is invalid, we try to collect accessible contexts from the current
+ // scope with a dummy lookup so that the completion consumer can try to
+ // guess what the specified scope is.
+ ResultBuilder DummyResults(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(), CC);
+ if (!PreferredType.isNull())
+ DummyResults.setPreferredType(PreferredType);
+ if (S->getEntity()) {
+ CodeCompletionDeclConsumer Consumer(DummyResults, S->getEntity(),
+ BaseType);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer,
+ /*IncludeGlobalScope=*/false,
+ /*LoadExternal=*/false);
+ }
+ HandleCodeCompleteResults(this, CodeCompleter,
+ DummyResults.getCompletionContext(), nullptr, 0);
return;
}
// Always pretend to enter a context to ensure that a dependent type
@@ -4988,9 +5368,12 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx))
return;
- ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompleter->getCodeCompletionTUInfo(),
- CodeCompletionContext::CCC_Symbol);
+ ResultBuilder Results(
+ *this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext(CodeCompletionContext::CCC_Symbol, PreferredType));
+ if (!PreferredType.isNull())
+ Results.setPreferredType(PreferredType);
Results.EnterNewScope();
// The "template" keyword can follow "::" in the grammar, but only
@@ -5149,9 +5532,10 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
&ResultBuilder::IsType);
Results.EnterNewScope();
- // Add the names of overloadable operators.
+ // Add the names of overloadable operators. Note that OO_Conditional is not
+ // actually overloadable.
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
- if (std::strcmp(Spelling, "?")) \
+ if (OO_##Name != OO_Conditional) \
Results.AddResult(Result(Spelling));
#include "clang/Basic/OperatorKinds.def"
@@ -6287,8 +6671,9 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
SourceLocation TemplateKWLoc;
UnqualifiedId id;
id.setIdentifier(Super, SuperLoc);
- ExprResult SuperExpr =
- ActOnIdExpression(S, SS, TemplateKWLoc, id, false, false);
+ ExprResult SuperExpr = ActOnIdExpression(S, SS, TemplateKWLoc, id,
+ /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(),
SelIdents, AtArgumentExpression);
}
@@ -8218,8 +8603,7 @@ void Sema::CodeCompletePreprocessorExpression() {
if (!CodeCompleter || CodeCompleter->includeMacros())
AddMacroResults(PP, Results,
- CodeCompleter ? CodeCompleter->loadExternal() : false,
- true);
+ !CodeCompleter || CodeCompleter->loadExternal(), true);
// defined (<macro>)
Results.EnterNewScope();
@@ -8258,7 +8642,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
// We need the native slashes for the actual file system interactions.
SmallString<128> NativeRelDir = StringRef(RelDir);
llvm::sys::path::native(NativeRelDir);
- auto FS = getSourceManager().getFileManager().getVirtualFileSystem();
+ llvm::vfs::FileSystem &FS =
+ getSourceManager().getFileManager().getVirtualFileSystem();
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
@@ -8284,20 +8669,39 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
};
// Helper: scans IncludeDir for nice files, and adds results for each.
- auto AddFilesFromIncludeDir = [&](StringRef IncludeDir, bool IsSystem) {
+ auto AddFilesFromIncludeDir = [&](StringRef IncludeDir,
+ bool IsSystem,
+ DirectoryLookup::LookupType_t LookupType) {
llvm::SmallString<128> Dir = IncludeDir;
- if (!NativeRelDir.empty())
- llvm::sys::path::append(Dir, NativeRelDir);
+ if (!NativeRelDir.empty()) {
+ if (LookupType == DirectoryLookup::LT_Framework) {
+ // For a framework dir, #include <Foo/Bar/> actually maps to
+ // a path of Foo.framework/Headers/Bar/.
+ auto Begin = llvm::sys::path::begin(NativeRelDir);
+ auto End = llvm::sys::path::end(NativeRelDir);
+
+ llvm::sys::path::append(Dir, *Begin + ".framework", "Headers");
+ llvm::sys::path::append(Dir, ++Begin, End);
+ } else {
+ llvm::sys::path::append(Dir, NativeRelDir);
+ }
+ }
std::error_code EC;
unsigned Count = 0;
- for (auto It = FS->dir_begin(Dir, EC);
+ for (auto It = FS.dir_begin(Dir, EC);
!EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {
if (++Count == 2500) // If we happen to hit a huge directory,
break; // bail out early so we're not too slow.
StringRef Filename = llvm::sys::path::filename(It->path());
switch (It->type()) {
case llvm::sys::fs::file_type::directory_file:
+ // All entries in a framework directory must have a ".framework" suffix,
+ // but the suffix does not appear in the source code's include/import.
+ if (LookupType == DirectoryLookup::LT_Framework &&
+ NativeRelDir.empty() && !Filename.consume_back(".framework"))
+ break;
+
AddCompletion(Filename, /*IsDirectory=*/true);
break;
case llvm::sys::fs::file_type::regular_file:
@@ -8326,10 +8730,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
// header maps are not (currently) enumerable.
break;
case DirectoryLookup::LT_NormalDir:
- AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem);
+ AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem,
+ DirectoryLookup::LT_NormalDir);
break;
case DirectoryLookup::LT_Framework:
- AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem);
+ AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem,
+ DirectoryLookup::LT_Framework);
break;
}
};
@@ -8343,7 +8749,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
// The current directory is on the include path for "quoted" includes.
auto *CurFile = PP.getCurrentFileLexer()->getFileEntry();
if (CurFile && CurFile->getDir())
- AddFilesFromIncludeDir(CurFile->getDir()->getName(), false);
+ AddFilesFromIncludeDir(CurFile->getDir()->getName(), false,
+ DirectoryLookup::LT_NormalDir);
for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end()))
AddFilesFromDirLookup(D, false);
}
@@ -8393,8 +8800,7 @@ void Sema::GatherGlobalCodeCompletions(
if (!CodeCompleter || CodeCompleter->includeMacros())
AddMacroResults(PP, Builder,
- CodeCompleter ? CodeCompleter->loadExternal() : false,
- true);
+ !CodeCompleter || CodeCompleter->loadExternal(), true);
Results.clear();
Results.insert(Results.end(), Builder.data(),
diff --git a/lib/Sema/SemaConsumer.cpp b/lib/Sema/SemaConsumer.cpp
index d83a13e2f175..02623be00c9c 100644
--- a/lib/Sema/SemaConsumer.cpp
+++ b/lib/Sema/SemaConsumer.cpp
@@ -1,9 +1,8 @@
//===-- SemaConsumer.cpp - Abstract interface for AST semantics -*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index 181efa6d3dd0..f0347af6a1bb 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -1,9 +1,8 @@
-//===--- SemaCoroutines.cpp - Semantic Analysis for Coroutines ------------===//
+//===-- SemaCoroutine.cpp - Semantic Analysis for Coroutines --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -186,21 +185,8 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
StringRef Keyword) {
- // 'co_await' and 'co_yield' are not permitted in unevaluated operands,
- // such as subexpressions of \c sizeof.
- //
- // [expr.await]p2, emphasis added: "An await-expression shall appear only in
- // a *potentially evaluated* expression within the compound-statement of a
- // function-body outside of a handler [...] A context within a function where
- // an await-expression can appear is called a suspension context of the
- // function." And per [expr.yield]p1: "A yield-expression shall appear only
- // within a suspension context of a function."
- if (S.isUnevaluatedContext()) {
- S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
- return false;
- }
-
- // Per [expr.await]p2, any other usage must be within a function.
+ // [expr.await]p2 dictates that 'co_await' and 'co_yield' must be used within
+ // a function body.
// FIXME: This also covers [expr.await]p2: "An await-expression shall not
// appear in a default argument." But the diagnostic QoI here could be
// improved to inform the user that default arguments specifically are not
@@ -218,12 +204,11 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
enum InvalidFuncDiag {
DiagCtor = 0,
DiagDtor,
- DiagCopyAssign,
- DiagMoveAssign,
DiagMain,
DiagConstexpr,
DiagAutoRet,
DiagVarargs,
+ DiagConsteval,
};
bool Diagnosed = false;
auto DiagInvalid = [&](InvalidFuncDiag ID) {
@@ -232,23 +217,15 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
return false;
};
- // Diagnose when a constructor, destructor, copy/move assignment operator,
+ // Diagnose when a constructor, destructor
// or the function 'main' are declared as a coroutine.
auto *MD = dyn_cast<CXXMethodDecl>(FD);
- // [class.ctor]p6: "A constructor shall not be a coroutine."
+ // [class.ctor]p11: "A constructor shall not be a coroutine."
if (MD && isa<CXXConstructorDecl>(MD))
return DiagInvalid(DiagCtor);
// [class.dtor]p17: "A destructor shall not be a coroutine."
else if (MD && isa<CXXDestructorDecl>(MD))
return DiagInvalid(DiagDtor);
- // N4499 [special]p6: "A special member function shall not be a coroutine."
- // Per C++ [special]p1, special member functions are the "default constructor,
- // copy constructor and copy assignment operator, move constructor and move
- // assignment operator, and destructor."
- else if (MD && MD->isCopyAssignmentOperator())
- return DiagInvalid(DiagCopyAssign);
- else if (MD && MD->isMoveAssignmentOperator())
- return DiagInvalid(DiagMoveAssign);
// [basic.start.main]p3: "The function main shall not be a coroutine."
else if (FD->isMain())
return DiagInvalid(DiagMain);
@@ -258,7 +235,7 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
// evaluation of e [...] would evaluate one of the following expressions:
// [...] an await-expression [...] a yield-expression."
if (FD->isConstexpr())
- DiagInvalid(DiagConstexpr);
+ DiagInvalid(FD->isConsteval() ? DiagConsteval : DiagConstexpr);
// [dcl.spec.auto]p15: "A function declared with a return type that uses a
// placeholder type shall not be a coroutine."
if (FD->getReturnType()->isUndeducedType())
@@ -326,7 +303,7 @@ static Expr *buildBuiltinCall(Sema &S, SourceLocation Loc, Builtin::ID Id,
assert(DeclRef.isUsable() && "Builtin reference cannot fail");
ExprResult Call =
- S.ActOnCallExpr(/*Scope=*/nullptr, DeclRef.get(), Loc, CallArgs, Loc);
+ S.BuildCallExpr(/*Scope=*/nullptr, DeclRef.get(), Loc, CallArgs, Loc);
assert(!Call.isInvalid() && "Call to builtin cannot fail!");
return Call.get();
@@ -356,7 +333,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
if (FromAddr.isInvalid())
return ExprError();
- return S.ActOnCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc);
+ return S.BuildCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc);
}
struct ReadySuspendResumeResult {
@@ -388,7 +365,7 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
return ExprError();
}
- return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
+ return S.BuildCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
}
// See if return type is coroutine-handle and if so, invoke builtin coro-resume
@@ -669,12 +646,57 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
return true;
}
+// Recursively walks up the scope hierarchy until either a 'catch' or a function
+// scope is found, whichever comes first.
+static bool isWithinCatchScope(Scope *S) {
+ // 'co_await' and 'co_yield' keywords are disallowed within catch blocks, but
+ // lambdas that use 'co_await' are allowed. The loop below ends when a
+ // function scope is found in order to ensure the following behavior:
+ //
+ // void foo() { // <- function scope
+ // try { //
+ // co_await x; // <- 'co_await' is OK within a function scope
+ // } catch { // <- catch scope
+ // co_await x; // <- 'co_await' is not OK within a catch scope
+ // []() { // <- function scope
+ // co_await x; // <- 'co_await' is OK within a function scope
+ // }();
+ // }
+ // }
+ while (S && !(S->getFlags() & Scope::FnScope)) {
+ if (S->getFlags() & Scope::CatchScope)
+ return true;
+ S = S->getParent();
+ }
+ return false;
+}
+
+// [expr.await]p2, emphasis added: "An await-expression shall appear only in
+// a *potentially evaluated* expression within the compound-statement of a
+// function-body *outside of a handler* [...] A context within a function
+// where an await-expression can appear is called a suspension context of the
+// function."
+static void checkSuspensionContext(Sema &S, SourceLocation Loc,
+ StringRef Keyword) {
+ // First emphasis of [expr.await]p2: must be a potentially evaluated context.
+ // That is, 'co_await' and 'co_yield' cannot appear in subexpressions of
+ // \c sizeof.
+ if (S.isUnevaluatedContext())
+ S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
+
+ // Second emphasis of [expr.await]p2: must be outside of an exception handler.
+ if (isWithinCatchScope(S.getCurScope()))
+ S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword;
+}
+
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
+ checkSuspensionContext(*this, Loc, "co_await");
+
if (E->getType()->isPlaceholderType()) {
ExprResult R = CheckPlaceholderExpr(E);
if (R.isInvalid()) return ExprError();
@@ -772,6 +794,8 @@ ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
return ExprError();
}
+ checkSuspensionContext(*this, Loc, "co_yield");
+
// Build yield_value call.
ExprResult Awaitable = buildPromiseCall(
*this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
@@ -1072,7 +1096,7 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
return false;
ExprResult ReturnObjectOnAllocationFailure =
- S.ActOnCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc);
+ S.BuildCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc);
if (ReturnObjectOnAllocationFailure.isInvalid())
return false;
@@ -1235,7 +1259,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
NewArgs.push_back(Arg);
ExprResult NewExpr =
- S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
+ S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
NewExpr = S.ActOnFinishFullExpr(NewExpr.get(), /*DiscardedValue*/ false);
if (NewExpr.isInvalid())
return false;
@@ -1261,7 +1285,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
DeleteArgs.push_back(FrameSize);
ExprResult DeleteExpr =
- S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
+ S.BuildCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
DeleteExpr =
S.ActOnFinishFullExpr(DeleteExpr.get(), /*DiscardedValue*/ false);
if (DeleteExpr.isInvalid())
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 23c99d45a78d..a6c52b7d4b2b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1,9 +1,8 @@
//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -23,6 +22,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -62,7 +62,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {
namespace {
-class TypeNameValidatorCCC : public CorrectionCandidateCallback {
+class TypeNameValidatorCCC final : public CorrectionCandidateCallback {
public:
TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false,
bool AllowTemplates = false,
@@ -106,6 +106,10 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
return !WantClassName && candidate.isKeyword();
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<TypeNameValidatorCCC>(*this);
+ }
+
private:
bool AllowInvalidDecl;
bool WantClassName;
@@ -368,11 +372,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
- TypoCorrection Correction =
- CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS,
- llvm::make_unique<TypeNameValidatorCCC>(
- true, isClassName, AllowDeducedTemplate),
- CTK_ErrorRecovery);
+ TypeNameValidatorCCC CCC(/*AllowInvalid=*/true, isClassName,
+ AllowDeducedTemplate);
+ TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), Kind,
+ S, SS, CCC, CTK_ErrorRecovery);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -665,11 +668,12 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
// 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.
+ TypeNameValidatorCCC CCC(/*AllowInvalid=*/false, /*WantClass=*/false,
+ /*AllowTemplates=*/IsTemplateName,
+ /*AllowNonTemplates=*/!IsTemplateName);
if (TypoCorrection Corrected =
CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS,
- llvm::make_unique<TypeNameValidatorCCC>(
- false, false, IsTemplateName, !IsTemplateName),
- CTK_ErrorRecovery)) {
+ CCC, CTK_ErrorRecovery)) {
// FIXME: Support error recovery for the template-name case.
bool CanRecover = !IsTemplateName;
if (Corrected.isKeyword()) {
@@ -712,7 +716,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S,
tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr,
/*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo=*/true);
+ /*WantNontrivialTypeSourceInfo=*/true);
}
return;
}
@@ -844,8 +848,7 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
Sema::NameClassification
Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
SourceLocation NameLoc, const Token &NextToken,
- bool IsAddressOfOperand,
- std::unique_ptr<CorrectionCandidateCallback> CCC) {
+ bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
@@ -915,6 +918,16 @@ Corrected:
}
}
+ if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
+ // In C++20 onwards, this could be an ADL-only call to a function
+ // template, and we're required to assume that this is a template name.
+ //
+ // FIXME: Find a way to still do typo correction in this case.
+ TemplateName Template =
+ Context.getAssumedTemplateName(NameInfo.getName());
+ return NameClassification::UndeclaredTemplate(Template);
+ }
+
// 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".
@@ -927,10 +940,9 @@ Corrected:
// close to this name.
if (!SecondTry && CCC) {
SecondTry = true;
- if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
- Result.getLookupKind(), S,
- &SS, std::move(CCC),
- CTK_ErrorRecovery)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
+ &SS, *CCC, CTK_ErrorRecovery)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
@@ -1018,7 +1030,8 @@ Corrected:
case LookupResult::Ambiguous:
if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
- hasAnyAcceptableTemplateNames(Result)) {
+ hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true,
+ /*AllowDependent=*/false)) {
// C++ [temp.local]p3:
// A lookup that finds an injected-class-name (10.2) can result in an
// ambiguity in certain cases (for example, if it is found in more than
@@ -1042,50 +1055,63 @@ Corrected:
}
if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
- (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) {
+ (IsFilteredTemplateName ||
+ hasAnyAcceptableTemplateNames(
+ Result, /*AllowFunctionTemplates=*/true,
+ /*AllowDependent=*/false,
+ /*AllowNonTemplateFunctions*/ !SS.isSet() &&
+ getLangOpts().CPlusPlus2a))) {
// 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
// this is followed by a <, the < is always taken as the delimiter of a
// template-argument-list and never as the less-than operator.
+ // C++2a [temp.names]p2:
+ // A name is also considered to refer to a template if it is an
+ // unqualified-id followed by a < and name lookup finds either one
+ // or more functions or finds nothing.
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(),
- Result.end());
- } else {
- TemplateDecl *TD
- = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl());
- IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
- IsVarTemplate = isa<VarTemplateDecl>(TD);
-
- if (SS.isSet() && !SS.isInvalid())
- 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();
+ bool IsFunctionTemplate;
+ bool IsVarTemplate;
+ TemplateName Template;
+ if (Result.end() - Result.begin() > 1) {
+ IsFunctionTemplate = true;
+ Template = Context.getOverloadedTemplateName(Result.begin(),
+ Result.end());
+ } else if (!Result.empty()) {
+ auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(
+ *Result.begin(), /*AllowFunctionTemplates=*/true,
+ /*AllowDependent=*/false));
+ IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
+ IsVarTemplate = isa<VarTemplateDecl>(TD);
+
+ if (SS.isSet() && !SS.isInvalid())
+ Template =
+ Context.getQualifiedTemplateName(SS.getScopeRep(),
+ /*TemplateKeyword=*/false, TD);
+ else
+ Template = TemplateName(TD);
+ } else {
+ // All results were non-template functions. This is a function template
+ // name.
+ IsFunctionTemplate = true;
+ Template = Context.getAssumedTemplateName(NameInfo.getName());
+ }
- return NameClassification::FunctionTemplate(Template);
- }
+ 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 IsVarTemplate ? NameClassification::VarTemplate(Template)
- : NameClassification::TypeTemplate(Template);
+ return NameClassification::FunctionTemplate(Template);
}
+
+ return IsVarTemplate ? NameClassification::VarTemplate(Template)
+ : NameClassification::TypeTemplate(Template);
}
NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
@@ -1164,6 +1190,8 @@ Sema::getTemplateNameKindForDiagnostics(TemplateName Name) {
return TemplateNameKindForDiagnostics::AliasTemplate;
if (isa<TemplateTemplateParmDecl>(TD))
return TemplateNameKindForDiagnostics::TemplateTemplateParam;
+ if (isa<ConceptDecl>(TD))
+ return TemplateNameKindForDiagnostics::Concept;
return TemplateNameKindForDiagnostics::DependentTemplate;
}
@@ -1399,11 +1427,6 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
}
}
-void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
- if (IdResolver.tryAddTopLevelDecl(D, Name) && TUScope)
- TUScope->AddDecl(D);
-}
-
bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S,
bool AllowInlineNamespace) {
return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace);
@@ -1461,12 +1484,17 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
Module *NewM = New->getOwningModule();
Module *OldM = Old->getOwningModule();
+
+ if (NewM && NewM->Kind == Module::PrivateModuleFragment)
+ NewM = NewM->Parent;
+ if (OldM && OldM->Kind == Module::PrivateModuleFragment)
+ OldM = OldM->Parent;
+
if (NewM == OldM)
return false;
- // FIXME: Check proclaimed-ownership-declarations here too.
- bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit;
- bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit;
+ bool NewIsModuleInterface = NewM && NewM->isModulePurview();
+ bool OldIsModuleInterface = OldM && OldM->isModulePurview();
if (NewIsModuleInterface || OldIsModuleInterface) {
// C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]:
// if a declaration of D [...] appears in the purview of a module, all
@@ -1862,10 +1890,10 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
if (!IDecl && DoTypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- if (TypoCorrection C = CorrectTypo(
- DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, nullptr,
- llvm::make_unique<DeclFilterCCC<ObjCInterfaceDecl>>(),
- CTK_ErrorRecovery)) {
+ DeclFilterCCC<ObjCInterfaceDecl> CCC{};
+ if (TypoCorrection C =
+ CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName,
+ TUScope, nullptr, CCC, CTK_ErrorRecovery)) {
diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Id = IDecl->getIdentifier();
@@ -1927,10 +1955,13 @@ static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S,
Context.setObjCSuperType(Context.getTagDeclType(TD));
}
-static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) {
+static StringRef getHeaderName(Builtin::Context &BuiltinInfo, unsigned ID,
+ ASTContext::GetBuiltinTypeError Error) {
switch (Error) {
case ASTContext::GE_None:
return "";
+ case ASTContext::GE_Missing_type:
+ return BuiltinInfo.getHeaderName(ID);
case ASTContext::GE_Missing_stdio:
return "stdio.h";
case ASTContext::GE_Missing_setjmp:
@@ -1955,7 +1986,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
if (Error) {
if (ForRedeclaration)
Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
- << getHeaderName(Error) << Context.BuiltinInfo.getName(ID);
+ << getHeaderName(Context.BuiltinInfo, ID, Error)
+ << Context.BuiltinInfo.getName(ID);
return nullptr;
}
@@ -2427,13 +2459,11 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
InheritableAttr *NewAttr = nullptr;
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
- NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
- AA->isImplicit(), AA->getIntroduced(),
- AA->getDeprecated(),
- AA->getObsoleted(), AA->getUnavailable(),
- AA->getMessage(), AA->getStrict(),
- AA->getReplacement(), AMK,
- AttrSpellingListIndex);
+ NewAttr = S.mergeAvailabilityAttr(
+ D, AA->getRange(), AA->getPlatform(), AA->isImplicit(),
+ AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(),
+ AA->getUnavailable(), AA->getMessage(), AA->getStrict(),
+ AA->getReplacement(), AMK, AA->getPriority(), AttrSpellingListIndex);
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
AttrSpellingListIndex);
@@ -2489,6 +2519,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
UA->getGuid());
+ else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
+ NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
+ else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
+ NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
@@ -2926,7 +2960,8 @@ static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A,
const auto *AttrB = B->getAttr<PassObjectSizeAttr>();
if (AttrA == AttrB)
return true;
- return AttrA && AttrB && AttrA->getType() == AttrB->getType();
+ return AttrA && AttrB && AttrA->getType() == AttrB->getType() &&
+ AttrA->isDynamic() == AttrB->isDynamic();
};
return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq);
@@ -3126,6 +3161,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// there but not here.
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
+ } else if (New->getBuiltinID()) {
+ // Calling Conventions on a Builtin aren't really useful and setting a
+ // default calling convention and cdecl'ing some builtin redeclarations is
+ // common, so warn and ignore the calling convention on the redeclaration.
+ Diag(New->getLocation(), diag::warn_cconv_unsupported)
+ << FunctionType::getNameForCallConv(NewTypeInfo.getCC())
+ << (int)CallingConventionIgnoredReason::BuiltinFunction;
+ NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
+ RequiresAdjustment = true;
} else {
// Calling conventions aren't compatible, so complain.
bool FirstCCExplicit = getCallingConvAttributedType(First->getType());
@@ -3194,7 +3238,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo);
New->setType(QualType(AdjustedType, 0));
NewQType = Context.getCanonicalType(New->getType());
- NewType = cast<FunctionType>(NewQType);
}
// If this redeclaration makes the function inline, we may need to add it to
@@ -4251,14 +4294,18 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
<< getLangOpts().CPlusPlus17;
- if (DS.isConstexprSpecified()) {
+ if (DS.hasConstexprSpecifier()) {
// C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations
// and definitions of functions and variables.
+ // C++2a [dcl.constexpr]p1: The consteval specifier shall be applied only to
+ // the declaration of a function or function template
+ bool IsConsteval = DS.getConstexprSpecifier() == CSK_consteval;
if (Tag)
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
- << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType());
+ << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << IsConsteval;
else
- Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators);
+ Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind)
+ << IsConsteval;
// Don't emit warnings after this error.
return TagD;
}
@@ -4796,6 +4843,18 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
+ // C++ [dcl.dcl]p3:
+ // [If there are no declarators], and except for the declaration of an
+ // unnamed bit-field, the decl-specifier-seq shall introduce one or more
+ // names into the program
+ // C++ [class.mem]p2:
+ // each such member-declaration shall either declare at least one member
+ // name of the class or declare at least one unnamed bit-field
+ //
+ // For C this is an error even for a named struct, and is diagnosed elsewhere.
+ if (getLangOpts().CPlusPlus && Record->field_empty())
+ Diag(DS.getBeginLoc(), diag::ext_no_declarators) << DS.getSourceRange();
+
// Mock up a declarator.
Declarator Dc(DS, DeclaratorContext::MemberContext);
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
@@ -5082,7 +5141,7 @@ static bool hasSimilarParameters(ASTContext &Context,
QualType DefParamTy = Definition->getParamDecl(Idx)->getType();
// The parameter types are identical
- if (Context.hasSameType(DefParamTy, DeclParamTy))
+ if (Context.hasSameUnqualifiedType(DefParamTy, DeclParamTy))
continue;
QualType DeclParamBaseTy = getCoreType(DeclParamTy);
@@ -5672,7 +5731,7 @@ void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
Diag(DS.getVirtualSpecLoc(),
diag::err_virtual_non_function);
- if (DS.isExplicitSpecified())
+ if (DS.hasExplicitSpecifier())
Diag(DS.getExplicitSpecLoc(),
diag::err_explicit_non_function);
@@ -5699,9 +5758,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
<< getLangOpts().CPlusPlus17;
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().hasConstexprSpecifier())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 1;
+ << 1 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) {
if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName)
@@ -5955,10 +6014,24 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
}
if (const InheritableAttr *Attr = getDLLAttr(&ND)) {
+ auto *VD = dyn_cast<VarDecl>(&ND);
+ bool IsAnonymousNS = false;
+ bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft();
+ if (VD) {
+ const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(VD->getDeclContext());
+ while (NS && !IsAnonymousNS) {
+ IsAnonymousNS = NS->isAnonymousNamespace();
+ NS = dyn_cast<NamespaceDecl>(NS->getParent());
+ }
+ }
// dll attributes require external linkage. Static locals may have external
// linkage but still cannot be explicitly imported or exported.
- auto *VD = dyn_cast<VarDecl>(&ND);
- if (!ND.isExternallyVisible() || (VD && VD->isStaticLocal())) {
+ // In Microsoft mode, a variable defined in anonymous namespace must have
+ // external linkage in order to be exported.
+ bool AnonNSInMicrosoftMode = IsAnonymousNS && IsMicrosoft;
+ if ((ND.isExternallyVisible() && AnonNSInMicrosoftMode) ||
+ (!AnonNSInMicrosoftMode &&
+ (!ND.isExternallyVisible() || (VD && VD->isStaticLocal())))) {
S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern)
<< &ND << Attr;
ND.setInvalidDecl();
@@ -6187,7 +6260,8 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) {
static bool shouldConsiderLinkage(const VarDecl *VD) {
const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC))
+ if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC) ||
+ isa<OMPDeclareMapperDecl>(DC))
return VD->hasExternalStorage();
if (DC->isFileContext())
return true;
@@ -6199,7 +6273,7 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
static bool shouldConsiderLinkage(const FunctionDecl *FD) {
const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
if (DC->isFileContext() || DC->isFunctionOrMethod() ||
- isa<OMPDeclareReductionDecl>(DC))
+ isa<OMPDeclareReductionDecl>(DC) || isa<OMPDeclareMapperDecl>(DC))
return true;
if (DC->isRecord())
return false;
@@ -6354,8 +6428,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- // OpenCL C++ 1.0 s2.9: the thread_local storage qualifier is not
- // supported. OpenCL C does not support thread_local either, and
+ // C++ for OpenCL does not allow the thread_local storage qualifier.
+ // OpenCL C does not support thread_local either, and
// also reject all other thread storage class specifiers.
DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec();
if (TSC != TSCS_unspecified) {
@@ -6431,6 +6505,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (D.isInvalidType())
NewVD->setInvalidDecl();
+
+ if (NewVD->getType().hasNonTrivialToPrimitiveDestructCUnion() &&
+ NewVD->hasLocalStorage())
+ checkNonTrivialCUnion(NewVD->getType(), NewVD->getLocation(),
+ NTCUC_AutoVar, NTCUK_Destruct);
} else {
bool Invalid = false;
@@ -6580,13 +6659,17 @@ NamedDecl *Sema::ActOnVariableDeclarator(
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
- if (D.getDeclSpec().isConstexprSpecified()) {
+ if (D.getDeclSpec().hasConstexprSpecifier()) {
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().CPlusPlus17)
NewVD->setImplicitlyInline();
+ if (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval)
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constexpr_wrong_decl_kind)
+ << /*consteval*/ 1;
}
}
@@ -7352,9 +7435,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// OpenCL C 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.
- // OpenCL C++ v1.0 s2.5 inherits rule from OpenCL C v2.0 and allows local
- // address space additionally.
- // FIXME: Add local AS for OpenCL C++.
+ // C++ for OpenCL inherits rule from OpenCL C v2.0.
+ // FIXME: Adding local AS in C++ for OpenCL might make sense.
if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() ||
NewVD->hasExternalStorage()) {
if (!T->isSamplerT() &&
@@ -7408,7 +7490,10 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
}
- } else if (T.getAddressSpace() != LangAS::opencl_private) {
+ } else if (T.getAddressSpace() != LangAS::opencl_private &&
+ // If we are parsing a template we didn't deduce an addr
+ // space yet.
+ T.getAddressSpace() != LangAS::Default) {
// Do not allow other address spaces on automatic variable.
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
NewVD->setInvalidDecl();
@@ -7654,7 +7739,7 @@ namespace {
// Callback to only accept typo corrections that have a non-zero edit distance.
// Also only accept corrections that have the same parent decl.
-class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
+class DifferentNameValidatorCCC final : public CorrectionCandidateCallback {
public:
DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD,
CXXRecordDecl *Parent)
@@ -7686,6 +7771,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
return false;
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<DifferentNameValidatorCCC>(*this);
+ }
+
private:
ASTContext &Context;
FunctionDecl *OriginalFD;
@@ -7733,6 +7822,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
assert(!Prev.isAmbiguous() &&
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ DifferentNameValidatorCCC CCC(SemaRef.Context, NewFD,
+ MD ? MD->getParent() : nullptr);
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -7749,10 +7840,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
// If the qualified name lookup yielded nothing, try typo correction
} else if ((Correction = SemaRef.CorrectTypo(
Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
- &ExtraArgs.D.getCXXScopeSpec(),
- llvm::make_unique<DifferentNameValidatorCCC>(
- SemaRef.Context, NewFD, MD ? MD->getParent() : nullptr),
- Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) {
+ &ExtraArgs.D.getCXXScopeSpec(), CCC, Sema::CTK_ErrorRecovery,
+ IsLocalFriend ? nullptr : NewDC))) {
// Set up everything for the call to ActOnFunctionDeclarator
ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
ExtraArgs.D.getIdentifierLoc());
@@ -7910,16 +7999,16 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
(!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
- R, TInfo, SC, isInline, HasPrototype, false);
+ R, TInfo, SC, isInline, HasPrototype,
+ CSK_unspecified);
if (D.isInvalidType())
NewFD->setInvalidDecl();
return NewFD;
}
- bool isExplicit = D.getDeclSpec().isExplicitSpecified();
- bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
-
+ ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
+ ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
@@ -7937,8 +8026,8 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
R = SemaRef.CheckConstructorDeclarator(D, R, SC);
return CXXConstructorDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, isExplicit, isInline,
- /*isImplicitlyDeclared=*/false, isConstexpr);
+ TInfo, ExplicitSpecifier, isInline,
+ /*isImplicitlyDeclared=*/false, ConstexprKind);
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
@@ -7968,7 +8057,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
D.getIdentifierLoc(), Name, R, TInfo, SC,
isInline,
- /*hasPrototype=*/true, isConstexpr);
+ /*hasPrototype=*/true, ConstexprKind);
}
} else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -7982,13 +8071,13 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, isInline, isExplicit, isConstexpr, SourceLocation());
+ TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation());
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
- isExplicit, NameInfo, R, TInfo,
+ ExplicitSpecifier, NameInfo, R, TInfo,
D.getEndLoc());
} else if (DC->isRecord()) {
// If the name of the function is the same as the name of the record,
@@ -8006,7 +8095,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// This is a C++ method declaration.
CXXMethodDecl *Ret = CXXMethodDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, SC, isInline, isConstexpr, SourceLocation());
+ TInfo, SC, isInline, ConstexprKind, SourceLocation());
IsVirtualOkay = !Ret->isStatic();
return Ret;
} else {
@@ -8020,7 +8109,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
R, TInfo, SC, isInline, true /*HasPrototype*/,
- isConstexpr);
+ ConstexprKind);
}
}
@@ -8044,8 +8133,7 @@ static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) {
QualType DesugaredTy = Ty;
do {
ArrayRef<StringRef> Names(SizeTypeNames);
- auto Match =
- std::find(Names.begin(), Names.end(), DesugaredTy.getAsString());
+ auto Match = llvm::find(Names, DesugaredTy.getAsString());
if (Names.end() != Match)
return true;
@@ -8350,8 +8438,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
- bool isExplicit = D.getDeclSpec().isExplicitSpecified();
- bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+ bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
+ ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
isFriend = D.getDeclSpec().isFriendSpecified();
if (isFriend && !isInline && D.isFunctionDefinition()) {
// C++ [class.friend]p5
@@ -8533,24 +8621,24 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The explicit specifier shall be used only in the declaration of a
// constructor or conversion function within its class definition;
// see 12.3.1 and 12.3.2.
- if (isExplicit && !NewFD->isInvalidDecl() &&
+ if (hasExplicit && !NewFD->isInvalidDecl() &&
!isa<CXXDeductionGuideDecl>(NewFD)) {
if (!CurContext->isRecord()) {
// 'explicit' was specified outside of the class.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_out_of_class)
- << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
} 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());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
}
}
- if (isConstexpr) {
+ if (ConstexprKind != CSK_unspecified) {
// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
NewFD->setImplicitlyInline();
@@ -8559,7 +8647,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
if (isa<CXXDestructorDecl>(NewFD))
- Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor)
+ << (ConstexprKind == CSK_consteval);
}
// If __module_private__ was specified, mark the function accordingly.
@@ -8620,8 +8709,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Complain about the 'static' specifier if it's on an out-of-line
// member function definition.
+
+ // MSVC permits the use of a 'static' storage specifier on an out-of-line
+ // member function template declaration and class member template
+ // declaration (MSVC versions before 2015), warn about this.
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- diag::err_static_out_of_line)
+ ((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
+ cast<CXXRecordDecl>(DC)->getDescribedClassTemplate()) ||
+ (getLangOpts().MSVCCompat && NewFD->getDescribedFunctionTemplate()))
+ ? diag::ext_static_out_of_line : diag::err_static_out_of_line)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
@@ -8836,6 +8932,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< FunctionType::getNameForCallConv(CC);
}
}
+
+ if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() ||
+ NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(NewFD->getReturnType(),
+ NewFD->getReturnTypeSourceRange().getBegin(),
+ NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy);
} else {
// C++11 [replacement.functions]p3:
// The program's definitions shall not be specified as inline.
@@ -9031,8 +9133,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// nothing will diagnose that error later.
if (isFriend &&
(D.getCXXScopeSpec().getScopeRep()->isDependent() ||
- (!Previous.empty() && (TemplateParamLists.size() ||
- CurContext->isDependentContext())))) {
+ (!Previous.empty() && CurContext->isDependentContext()))) {
// ignore these
} else {
// The user tried to provide an out-of-line definition for a
@@ -9137,13 +9238,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().CUDA) {
IdentifierInfo *II = NewFD->getIdentifier();
- if (II &&
- II->isStr(getLangOpts().HIP ? "hipConfigureCall"
- : "cudaConfigureCall") &&
+ if (II && II->isStr(getCudaConfigureFuncName()) &&
!NewFD->isInvalidDecl() &&
NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
if (!R->getAs<FunctionType>()->getReturnType()->isScalarType())
- Diag(NewFD->getLocation(), diag::err_config_scalar_return);
+ Diag(NewFD->getLocation(), diag::err_config_scalar_return)
+ << getCudaConfigureFuncName();
Context.setcudaConfigureCallDecl(NewFD);
}
@@ -9161,18 +9261,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
MarkUnusedFileScopedDecl(NewFD);
- if (getLangOpts().CPlusPlus) {
- if (FunctionTemplate) {
- if (NewFD->isInvalidDecl())
- FunctionTemplate->setInvalidDecl();
- return FunctionTemplate;
- }
- if (isMemberSpecialization && !NewFD->isInvalidDecl())
- CompleteMemberSpecialization(NewFD, Previous);
- }
- if (NewFD->hasAttr<OpenCLKernelAttr>()) {
+ if (getLangOpts().OpenCL && NewFD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL v1.2 s6.8 static is invalid for kernel functions.
if ((getLangOpts().OpenCLVersion >= 120)
&& (SC == SC_Static)) {
@@ -9192,13 +9283,36 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
llvm::SmallPtrSet<const Type *, 16> ValidTypes;
for (auto Param : NewFD->parameters())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
+
+ if (getLangOpts().OpenCLCPlusPlus) {
+ if (DC->isRecord()) {
+ Diag(D.getIdentifierLoc(), diag::err_method_kernel);
+ D.setInvalidType();
+ }
+ if (FunctionTemplate) {
+ Diag(D.getIdentifierLoc(), diag::err_template_kernel);
+ D.setInvalidType();
+ }
+ }
}
+
+ if (getLangOpts().CPlusPlus) {
+ if (FunctionTemplate) {
+ if (NewFD->isInvalidDecl())
+ FunctionTemplate->setInvalidDecl();
+ return FunctionTemplate;
+ }
+
+ if (isMemberSpecialization && !NewFD->isInvalidDecl())
+ CompleteMemberSpecialization(NewFD, Previous);
+ }
+
for (const ParmVarDecl *Param : NewFD->parameters()) {
QualType PT = Param->getType();
// OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value
// types.
- if (getLangOpts().OpenCLVersion >= 200) {
+ if (getLangOpts().OpenCLVersion >= 200 || getLangOpts().OpenCLCPlusPlus) {
if(const PipeType *PipeTy = PT->getAs<PipeType>()) {
QualType ElemTy = PipeTy->getElementType();
if (ElemTy->isReferenceType() || ElemTy->isPointerType()) {
@@ -9437,6 +9551,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
DeletedFuncs = 5,
DefaultedFuncs = 6,
ConstexprFuncs = 7,
+ ConstevalFuncs = 8,
};
enum Different {
CallingConv = 0,
@@ -9512,7 +9627,8 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch ||
MVType == MultiVersionKind::CPUSpecific))
return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << ConstexprFuncs;
+ << IsCPUSpecificCPUDispatchMVType
+ << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType());
const auto *NewType = cast<FunctionType>(NewQType);
@@ -9543,7 +9659,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
<< ReturnType;
- if (OldFD->isConstexpr() != NewFD->isConstexpr())
+ if (OldFD->getConstexprKind() != NewFD->getConstexprKind())
return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
<< ConstexprSpec;
@@ -9575,9 +9691,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
/// Returns true if there was an error, false otherwise.
static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD,
MultiVersionKind MVType,
- const TargetAttr *TA,
- const CPUDispatchAttr *CPUDisp,
- const CPUSpecificAttr *CPUSpec) {
+ const TargetAttr *TA) {
assert(MVType != MultiVersionKind::None &&
"Function lacks multiversion attribute");
@@ -9884,8 +9998,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
// multiversioning, this isn't an error condition.
if (MVType == MultiVersionKind::None)
return false;
- return CheckMultiVersionFirstFunction(S, NewFD, MVType, NewTA, NewCPUDisp,
- NewCPUSpec);
+ return CheckMultiVersionFirstFunction(S, NewFD, MVType, NewTA);
}
FunctionDecl *OldFD = OldDecl->getAsFunction();
@@ -10017,7 +10130,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() &&
!MD->isStatic() && !isa<CXXConstructorDecl>(MD) &&
- !MD->getTypeQualifiers().hasConst()) {
+ !MD->getMethodQualifiers().hasConst()) {
CXXMethodDecl *OldMD = nullptr;
if (OldDecl)
OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction());
@@ -10296,8 +10409,9 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
}
if (FD->isConstexpr()) {
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main)
- << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
- FD->setConstexpr(false);
+ << FD->isConsteval()
+ << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
+ FD->setConstexprKind(CSK_unspecified);
}
if (getLangOpts().OpenCL) {
@@ -10808,7 +10922,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
DeclarationName Name, QualType Type,
TypeSourceInfo *TSI,
SourceRange Range, bool DirectInit,
- Expr *&Init) {
+ Expr *Init) {
bool IsInitCapture = !VDecl;
assert((!VDecl || !VDecl->isInitCapture()) &&
"init captures are expected to be deduced prior to initialization");
@@ -10924,8 +11038,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
<< (DeduceInit->getType().isNull() ? TSI->getType()
: DeduceInit->getType())
<< DeduceInit->getSourceRange();
- } else
- Init = DeduceInit;
+ }
// Warn if we deduced 'id'. 'auto' usually implies type-safety, but using
// 'id' instead of a specific object type prevents most of our usual
@@ -10942,7 +11055,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
}
bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
- Expr *&Init) {
+ Expr *Init) {
QualType DeducedType = deduceVarTypeFromInitializer(
VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(),
VDecl->getSourceRange(), DirectInit, Init);
@@ -10971,6 +11084,264 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
return VDecl->isInvalidDecl();
}
+void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init,
+ SourceLocation Loc) {
+ if (auto *CE = dyn_cast<ConstantExpr>(Init))
+ Init = CE->getSubExpr();
+
+ QualType InitType = Init->getType();
+ assert((InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ InitType.hasNonTrivialToPrimitiveCopyCUnion()) &&
+ "shouldn't be called if type doesn't have a non-trivial C struct");
+ if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
+ for (auto I : ILE->inits()) {
+ if (!I->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() &&
+ !I->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ continue;
+ SourceLocation SL = I->getExprLoc();
+ checkNonTrivialCUnionInInitializer(I, SL.isValid() ? SL : Loc);
+ }
+ return;
+ }
+
+ if (isa<ImplicitValueInitExpr>(Init)) {
+ if (InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion())
+ checkNonTrivialCUnion(InitType, Loc, NTCUC_DefaultInitializedObject,
+ NTCUK_Init);
+ } else {
+ // Assume all other explicit initializers involving copying some existing
+ // object.
+ // TODO: ignore any explicit initializers where we can guarantee
+ // copy-elision.
+ if (InitType.hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(InitType, Loc, NTCUC_CopyInit, NTCUK_Copy);
+ }
+}
+
+namespace {
+
+struct DiagNonTrivalCUnionDefaultInitializeVisitor
+ : DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor,
+ void> {
+ using Super =
+ DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor,
+ void>;
+
+ DiagNonTrivalCUnionDefaultInitializeVisitor(
+ QualType OrigTy, SourceLocation OrigLoc,
+ Sema::NonTrivialCUnionContext UseContext, Sema &S)
+ : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {}
+
+ void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (const auto *AT = S.Context.getAsArrayType(QT))
+ return this->asDerived().visit(S.Context.getBaseElementType(AT), FD,
+ InNonTrivialUnion);
+ return Super::visitWithKind(PDIK, QT, FD, InNonTrivialUnion);
+ }
+
+ void visitARCStrong(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 0 << QT << FD->getName();
+ }
+
+ void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 0 << QT << FD->getName();
+ }
+
+ void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
+ if (RD->isUnion()) {
+ if (OrigLoc.isValid()) {
+ bool IsUnion = false;
+ if (auto *OrigRD = OrigTy->getAsRecordDecl())
+ IsUnion = OrigRD->isUnion();
+ S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context)
+ << 0 << OrigTy << IsUnion << UseContext;
+ // Reset OrigLoc so that this diagnostic is emitted only once.
+ OrigLoc = SourceLocation();
+ }
+ InNonTrivialUnion = true;
+ }
+
+ if (InNonTrivialUnion)
+ S.Diag(RD->getLocation(), diag::note_non_trivial_c_union)
+ << 0 << 0 << QT.getUnqualifiedType() << "";
+
+ for (const FieldDecl *FD : RD->fields())
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ }
+
+ void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
+
+ // The non-trivial C union type or the struct/union type that contains a
+ // non-trivial C union.
+ QualType OrigTy;
+ SourceLocation OrigLoc;
+ Sema::NonTrivialCUnionContext UseContext;
+ Sema &S;
+};
+
+struct DiagNonTrivalCUnionDestructedTypeVisitor
+ : DestructedTypeVisitor<DiagNonTrivalCUnionDestructedTypeVisitor, void> {
+ using Super =
+ DestructedTypeVisitor<DiagNonTrivalCUnionDestructedTypeVisitor, void>;
+
+ DiagNonTrivalCUnionDestructedTypeVisitor(
+ QualType OrigTy, SourceLocation OrigLoc,
+ Sema::NonTrivialCUnionContext UseContext, Sema &S)
+ : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {}
+
+ void visitWithKind(QualType::DestructionKind DK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (const auto *AT = S.Context.getAsArrayType(QT))
+ return this->asDerived().visit(S.Context.getBaseElementType(AT), FD,
+ InNonTrivialUnion);
+ return Super::visitWithKind(DK, QT, FD, InNonTrivialUnion);
+ }
+
+ void visitARCStrong(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 1 << QT << FD->getName();
+ }
+
+ void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 1 << QT << FD->getName();
+ }
+
+ void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
+ if (RD->isUnion()) {
+ if (OrigLoc.isValid()) {
+ bool IsUnion = false;
+ if (auto *OrigRD = OrigTy->getAsRecordDecl())
+ IsUnion = OrigRD->isUnion();
+ S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context)
+ << 1 << OrigTy << IsUnion << UseContext;
+ // Reset OrigLoc so that this diagnostic is emitted only once.
+ OrigLoc = SourceLocation();
+ }
+ InNonTrivialUnion = true;
+ }
+
+ if (InNonTrivialUnion)
+ S.Diag(RD->getLocation(), diag::note_non_trivial_c_union)
+ << 0 << 1 << QT.getUnqualifiedType() << "";
+
+ for (const FieldDecl *FD : RD->fields())
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ }
+
+ void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
+ void visitCXXDestructor(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {}
+
+ // The non-trivial C union type or the struct/union type that contains a
+ // non-trivial C union.
+ QualType OrigTy;
+ SourceLocation OrigLoc;
+ Sema::NonTrivialCUnionContext UseContext;
+ Sema &S;
+};
+
+struct DiagNonTrivalCUnionCopyVisitor
+ : CopiedTypeVisitor<DiagNonTrivalCUnionCopyVisitor, false, void> {
+ using Super = CopiedTypeVisitor<DiagNonTrivalCUnionCopyVisitor, false, void>;
+
+ DiagNonTrivalCUnionCopyVisitor(QualType OrigTy, SourceLocation OrigLoc,
+ Sema::NonTrivialCUnionContext UseContext,
+ Sema &S)
+ : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {}
+
+ void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (const auto *AT = S.Context.getAsArrayType(QT))
+ return this->asDerived().visit(S.Context.getBaseElementType(AT), FD,
+ InNonTrivialUnion);
+ return Super::visitWithKind(PCK, QT, FD, InNonTrivialUnion);
+ }
+
+ void visitARCStrong(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 2 << QT << FD->getName();
+ }
+
+ void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 2 << QT << FD->getName();
+ }
+
+ void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();
+ if (RD->isUnion()) {
+ if (OrigLoc.isValid()) {
+ bool IsUnion = false;
+ if (auto *OrigRD = OrigTy->getAsRecordDecl())
+ IsUnion = OrigRD->isUnion();
+ S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context)
+ << 2 << OrigTy << IsUnion << UseContext;
+ // Reset OrigLoc so that this diagnostic is emitted only once.
+ OrigLoc = SourceLocation();
+ }
+ InNonTrivialUnion = true;
+ }
+
+ if (InNonTrivialUnion)
+ S.Diag(RD->getLocation(), diag::note_non_trivial_c_union)
+ << 0 << 2 << QT.getUnqualifiedType() << "";
+
+ for (const FieldDecl *FD : RD->fields())
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ }
+
+ void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {}
+ void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
+ void visitVolatileTrivial(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {}
+
+ // The non-trivial C union type or the struct/union type that contains a
+ // non-trivial C union.
+ QualType OrigTy;
+ SourceLocation OrigLoc;
+ Sema::NonTrivialCUnionContext UseContext;
+ Sema &S;
+};
+
+} // namespace
+
+void Sema::checkNonTrivialCUnion(QualType QT, SourceLocation Loc,
+ NonTrivialCUnionContext UseContext,
+ unsigned NonTrivialKind) {
+ assert((QT.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ QT.hasNonTrivialToPrimitiveDestructCUnion() ||
+ QT.hasNonTrivialToPrimitiveCopyCUnion()) &&
+ "shouldn't be called if type doesn't have a non-trivial C union");
+
+ if ((NonTrivialKind & NTCUK_Init) &&
+ QT.hasNonTrivialToPrimitiveDefaultInitializeCUnion())
+ DiagNonTrivalCUnionDefaultInitializeVisitor(QT, Loc, UseContext, *this)
+ .visit(QT, nullptr, false);
+ if ((NonTrivialKind & NTCUK_Destruct) &&
+ QT.hasNonTrivialToPrimitiveDestructCUnion())
+ DiagNonTrivalCUnionDestructedTypeVisitor(QT, Loc, UseContext, *this)
+ .visit(QT, nullptr, false);
+ if ((NonTrivialKind & NTCUK_Copy) && QT.hasNonTrivialToPrimitiveCopyCUnion())
+ DiagNonTrivalCUnionCopyVisitor(QT, Loc, UseContext, *this)
+ .visit(QT, nullptr, false);
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -11218,7 +11589,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// do nothing
// OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized.
- // This is true even in OpenCL C++.
+ // This is true even in C++ for OpenCL.
} else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) {
CheckForConstantInitializer(Init, DclT);
@@ -11244,6 +11615,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
<< Culprit->getSourceRange();
}
}
+
+ if (auto *E = dyn_cast<ExprWithCleanups>(Init))
+ if (auto *BE = dyn_cast<BlockExpr>(E->getSubExpr()->IgnoreParens()))
+ if (VDecl->hasLocalStorage())
+ BE->getBlockDecl()->setCanAvoidCopyToHeap();
} else if (VDecl->isStaticDataMember() && !VDecl->isInline() &&
VDecl->getLexicalDeclContext()->isRecord()) {
// This is an in-class initialization for a static data member, e.g.,
@@ -11358,11 +11734,25 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
!isTemplateInstantiation(VDecl->getTemplateSpecializationKind()))
Diag(VDecl->getLocation(), diag::warn_extern_init);
+ // In Microsoft C++ mode, a const variable defined in namespace scope has
+ // external linkage by default if the variable is declared with
+ // __declspec(dllexport).
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ getLangOpts().CPlusPlus && VDecl->getType().isConstQualified() &&
+ VDecl->hasAttr<DLLExportAttr>() && VDecl->getDefinition())
+ VDecl->setStorageClass(SC_Extern);
+
// C99 6.7.8p4. All file scoped initializers need to be constant.
if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl())
CheckForConstantInitializer(Init, DclT);
}
+ QualType InitType = Init->getType();
+ if (!InitType.isNull() &&
+ (InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ InitType.hasNonTrivialToPrimitiveCopyCUnion()))
+ checkNonTrivialCUnionInInitializer(Init, Init->getExprLoc());
+
// We will represent direct-initialization similarly to copy-initialization:
// int x(1); -as-> int x = 1;
// ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
@@ -11448,9 +11838,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
- Expr *TmpInit = nullptr;
if (Type->isUndeducedType() &&
- DeduceVariableDeclarationType(Var, false, TmpInit))
+ DeduceVariableDeclarationType(Var, false, nullptr))
return;
// C++11 [class.static.data]p3: A static data member can be declared with
@@ -11488,7 +11877,14 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
- switch (Var->isThisDeclarationADefinition()) {
+ VarDecl::DefinitionKind DefKind = Var->isThisDeclarationADefinition();
+ if (!Var->isInvalidDecl() && DefKind != VarDecl::DeclarationOnly &&
+ Var->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion())
+ checkNonTrivialCUnion(Var->getType(), Var->getLocation(),
+ NTCUC_DefaultInitializedObject, NTCUK_Init);
+
+
+ switch (DefKind) {
case VarDecl::Definition:
if (!Var->isStaticDataMember() || !Var->getAnyInitializer())
break;
@@ -11627,7 +12023,11 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
setFunctionHasBranchProtectedScope();
}
}
-
+ // In OpenCL, we can't initialize objects in the __local address space,
+ // even implicitly, so don't synthesize an implicit initializer.
+ if (getLangOpts().OpenCL &&
+ Var->getType().getAddressSpace() == LangAS::opencl_local)
+ return;
// 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
@@ -11723,7 +12123,6 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
D.SetIdentifier(Ident, IdentLoc);
D.takeAttributes(Attrs, AttrEnd);
- ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory());
D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/ false),
IdentLoc);
Decl *Var = ActOnDeclarator(S, D);
@@ -11786,13 +12185,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
while (prev && prev->isThisDeclarationADefinition())
prev = prev->getPreviousDecl();
- if (!prev)
+ if (!prev) {
Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var;
+ Diag(var->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage)
+ << /* variable */ 0;
+ }
}
// Cache the result of checking for constant initialization.
Optional<bool> CacheHasConstInit;
- const Expr *CacheCulprit;
+ const Expr *CacheCulprit = nullptr;
auto checkConstInit = [&]() mutable {
if (!CacheHasConstInit)
CacheHasConstInit = var->getInit()->isConstantInitializer(
@@ -11893,7 +12295,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
Diag(Notes[I].first, Notes[I].second);
}
- } else if (var->isUsableInConstantExpressions(Context)) {
+ } else if (var->mightBeUsableInConstantExpressions(Context)) {
// Check whether the initializer of a const variable of integral or
// enumeration type is an ICE now, since we can't tell whether it was
// initialized by a constant expression if we check later.
@@ -12340,6 +12742,45 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
}
}
+/// Common checks for a parameter-declaration that should apply to both function
+/// parameters and non-type template parameters.
+void Sema::CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D) {
+ // Check that there are no default arguments inside the type of this
+ // parameter.
+ if (getLangOpts().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
+ if (D.getCXXScopeSpec().isSet()) {
+ Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
+ << D.getCXXScopeSpec().getRange();
+ }
+
+ // [dcl.meaning]p1: An unqualified-id occurring in a declarator-id shall be a
+ // simple identifier except [...irrelevant cases...].
+ switch (D.getName().getKind()) {
+ case UnqualifiedIdKind::IK_Identifier:
+ break;
+
+ case UnqualifiedIdKind::IK_OperatorFunctionId:
+ case UnqualifiedIdKind::IK_ConversionFunctionId:
+ case UnqualifiedIdKind::IK_LiteralOperatorId:
+ case UnqualifiedIdKind::IK_ConstructorName:
+ case UnqualifiedIdKind::IK_DestructorName:
+ case UnqualifiedIdKind::IK_ImplicitSelfParam:
+ case UnqualifiedIdKind::IK_DeductionGuideName:
+ Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name)
+ << GetNameForDeclarator(D).getName();
+ break;
+
+ case UnqualifiedIdKind::IK_TemplateId:
+ case UnqualifiedIdKind::IK_ConstructorTemplateId:
+ // GetNameForDeclarator would not produce a useful name in this case.
+ Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name_template_id);
+ break;
+ }
+}
+
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
@@ -12374,40 +12815,19 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (DS.isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
<< getLangOpts().CPlusPlus17;
- if (DS.isConstexprSpecified())
+ if (DS.hasConstexprSpecifier())
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 0;
+ << 0 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
DiagnoseFunctionSpecifiers(DS);
+ CheckFunctionOrTemplateParamDeclarator(S, D);
+
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
- if (getLangOpts().CPlusPlus) {
- // 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)
- << D.getCXXScopeSpec().getRange();
- D.getCXXScopeSpec().clear();
- }
- }
-
- // Ensure we have a valid name
- IdentifierInfo *II = nullptr;
- if (D.hasName()) {
- II = D.getIdentifier();
- if (!II) {
- Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name)
- << GetNameForDeclarator(D).getName();
- D.setInvalidType(true);
- }
- }
-
// Check for redeclaration of parameters, e.g. int foo(int x, int x);
+ IdentifierInfo *II = D.getIdentifier();
if (II) {
LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName,
ForVisibleRedeclaration);
@@ -12538,9 +12958,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// - otherwise, it's an error
if (T->isArrayType()) {
if (!T.isConstQualified()) {
- DelayedDiagnostics.add(
- sema::DelayedDiagnostic::makeForbiddenType(
- NameLoc, diag::err_arc_array_param_no_ownership, T, false));
+ if (DelayedDiagnostics.shouldDelayDiagnostics())
+ DelayedDiagnostics.add(
+ sema::DelayedDiagnostic::makeForbiddenType(
+ NameLoc, diag::err_arc_array_param_no_ownership, T, false));
+ else
+ Diag(NameLoc, diag::err_arc_array_param_no_ownership)
+ << TSInfo->getTypeLoc().getSourceRange();
}
lifetime = Qualifiers::OCL_ExplicitNone;
} else {
@@ -12553,6 +12977,11 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
+ if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
+ New->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(New->getType(), New->getLocation(),
+ NTCUC_FunctionParam, NTCUK_Destruct|NTCUK_Copy);
+
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
@@ -12642,8 +13071,9 @@ void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) {
Consumer.HandleInlineFunctionDefinition(D);
}
-static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
- const FunctionDecl*& PossibleZeroParamPrototype) {
+static bool
+ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
+ const FunctionDecl *&PossiblePrototype) {
// Don't warn about invalid declarations.
if (FD->isInvalidDecl())
return false;
@@ -12680,7 +13110,6 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (FD->isDeleted())
return false;
- bool MissingPrototype = true;
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
@@ -12688,13 +13117,11 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
continue;
- MissingPrototype = !Prev->getType()->isFunctionProtoType();
- if (FD->getNumParams() == 0)
- PossibleZeroParamPrototype = Prev;
- break;
+ PossiblePrototype = Prev;
+ return Prev->getType()->isFunctionNoProtoType();
}
- return MissingPrototype;
+ return true;
}
void
@@ -12834,14 +13261,14 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
/*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
/*EllipsisLoc*/C.isPackExpansion()
? C.getEllipsisLoc() : SourceLocation(),
- CaptureType, /*Expr*/ nullptr);
+ CaptureType, /*Invalid*/false);
} else if (C.capturesThis()) {
- LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
- /*Expr*/ nullptr,
- C.getCaptureKind() == LCK_StarThis);
+ LSI->addThisCapture(/*Nested*/ false, C.getLocation(), I->getType(),
+ C.getCaptureKind() == LCK_StarThis);
} else {
- LSI->addVLATypeCapture(C.getLocation(), I->getType());
+ LSI->addVLATypeCapture(C.getLocation(), I->getCapturedVLAType(),
+ I->getType());
}
++I;
}
@@ -13023,7 +13450,7 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
bool Sema::canDelayFunctionBody(const Declarator &D) {
// We can't delay parsing the body of a constexpr function template (yet).
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().hasConstexprSpecifier())
return false;
// We can't delay parsing the body of a function template with a deduced
@@ -13092,6 +13519,35 @@ private:
bool IsLambda = false;
};
+static void diagnoseImplicitlyRetainedSelf(Sema &S) {
+ llvm::DenseMap<const BlockDecl *, bool> EscapeInfo;
+
+ auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) {
+ if (EscapeInfo.count(BD))
+ return EscapeInfo[BD];
+
+ bool R = false;
+ const BlockDecl *CurBD = BD;
+
+ do {
+ R = !CurBD->doesNotEscape();
+ if (R)
+ break;
+ CurBD = CurBD->getParent()->getInnermostBlockDecl();
+ } while (CurBD);
+
+ return EscapeInfo[BD] = R;
+ };
+
+ // If the location where 'self' is implicitly retained is inside a escaping
+ // block, emit a diagnostic.
+ for (const std::pair<SourceLocation, const BlockDecl *> &P :
+ S.ImplicitlyRetainedSelfLocs)
+ if (IsOrNestedInEscapingBlock(P.second))
+ S.Diag(P.first, diag::warn_implicitly_retains_self)
+ << FixItHint::CreateInsertion(P.first, "self->");
+}
+
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
bool IsInstantiation) {
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
@@ -13099,7 +13555,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
- if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine())
+ if (getLangOpts().Coroutines && getCurFunction()->isCoroutine())
CheckCompletedCoroutineBody(FD, Body);
// Do not call PopExpressionEvaluationContext() if it is a lambda because one
@@ -13156,7 +13612,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// MSVC permits the use of pure specifier (=0) on function definition,
// defined at class scope, warn about this non-standard construct.
- if (getLangOpts().MicrosoftExt && FD->isPure() && FD->isCanonicalDecl())
+ if (getLangOpts().MicrosoftExt && FD->isPure() && !FD->isOutOfLine())
Diag(FD->getLocation(), diag::ext_pure_function_definition);
if (!FD->isInvalidDecl()) {
@@ -13185,22 +13641,30 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// prototype declaration. This warning is issued even if the
// definition itself provides a prototype. The aim is to detect
// global functions that fail to be declared in header files.
- const FunctionDecl *PossibleZeroParamPrototype = nullptr;
- if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
+ const FunctionDecl *PossiblePrototype = nullptr;
+ if (ShouldWarnAboutMissingPrototype(FD, PossiblePrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
- if (PossibleZeroParamPrototype) {
+ if (PossiblePrototype) {
// We found a declaration that is not a prototype,
// but that could be a zero-parameter prototype
- if (TypeSourceInfo *TI =
- PossibleZeroParamPrototype->getTypeSourceInfo()) {
+ if (TypeSourceInfo *TI = PossiblePrototype->getTypeSourceInfo()) {
TypeLoc TL = TI->getTypeLoc();
if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
- Diag(PossibleZeroParamPrototype->getLocation(),
+ Diag(PossiblePrototype->getLocation(),
diag::note_declaration_not_a_prototype)
- << PossibleZeroParamPrototype
- << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+ << (FD->getNumParams() != 0)
+ << (FD->getNumParams() == 0
+ ? FixItHint::CreateInsertion(FTL.getRParenLoc(), "void")
+ : FixItHint{});
}
+ } else {
+ Diag(FD->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage)
+ << /* function */ 1
+ << (FD->getStorageClass() == SC_None
+ ? FixItHint::CreateInsertion(FD->getTypeSpecStartLoc(),
+ "static ")
+ : FixItHint{});
}
// GNU warning -Wstrict-prototypes
@@ -13256,8 +13720,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
if (!MD->isInvalidDecl()) {
- if (!MD->hasSkippedBody())
- DiagnoseUnusedParameters(MD->parameters());
DiagnoseSizeOfParametersAndReturnValue(MD->parameters(),
MD->getReturnType(), MD);
@@ -13303,6 +13765,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
diag::warn_objc_secondary_init_missing_init_call);
getCurFunction()->ObjCWarnForNoInitDelegation = false;
}
+
+ diagnoseImplicitlyRetainedSelf(*this);
} else {
// Parsing the function declaration failed in some way. Pop the fake scope
// we pushed on.
@@ -13484,10 +13948,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// function declaration is going to be treated as an error.
if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) {
TypoCorrection Corrected;
- if (S &&
- (Corrected = CorrectTypo(
- DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, nullptr,
- llvm::make_unique<DeclFilterCCC<FunctionDecl>>(), CTK_NonError)))
+ DeclFilterCCC<FunctionDecl> CCC{};
+ if (S && (Corrected =
+ CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName,
+ S, nullptr, CCC, CTK_NonError)))
diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
/*ErrorRecovery*/false);
}
@@ -13576,6 +14040,13 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->getLocation()));
}
+ // Handle automatically recognized callbacks.
+ SmallVector<int, 4> Encoding;
+ if (!FD->hasAttr<CallbackAttr>() &&
+ Context.BuiltinInfo.performsCallback(BuiltinID, Encoding))
+ FD->addAttr(CallbackAttr::CreateImplicit(
+ Context, Encoding.data(), Encoding.size(), FD->getLocation()));
+
// Mark const if we don't care about errno and that is the only thing
// preventing the function from being const. This allows IRgen to use LLVM
// intrinsics for such functions.
@@ -14743,8 +15214,7 @@ CreateNewDecl:
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
- if (IsFixed && (getLangOpts().CPlusPlus11 || getLangOpts().ObjC) &&
- cast<EnumDecl>(New)->isFixed()) {
+ if (IsFixed && cast<EnumDecl>(New)->isFixed()) {
// C++0x: 7.2p2: opaque-enum-declaration.
// Conflicts are diagnosed above. Do nothing.
}
@@ -15758,7 +16228,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// Verify that all the fields are okay.
SmallVector<FieldDecl*, 32> RecFields;
- bool ObjCFieldLifetimeErrReported = false;
for (ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
i != end; ++i) {
FieldDecl *FD = cast<FieldDecl>(*i);
@@ -15903,27 +16372,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
- } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
- Record && !ObjCFieldLifetimeErrReported && Record->isUnion()) {
- // It's an error in ARC or Weak if a field has lifetime.
- // We don't want to report this in a system header, though,
- // so we just make the field unavailable.
- // FIXME: that's really not sufficient; we need to make the type
- // itself invalid to, say, initialize or copy.
- QualType T = FD->getType();
- if (T.hasNonTrivialObjCLifetime()) {
- SourceLocation loc = FD->getLocation();
- if (getSourceManager().isInSystemHeader(loc)) {
- if (!FD->hasAttr<UnavailableAttr>()) {
- FD->addAttr(UnavailableAttr::CreateImplicit(Context, "",
- UnavailableAttr::IR_ARCFieldWithOwnership, loc));
- }
- } else {
- Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
- << T->isBlockPointerType() << Record->getTagKind();
- }
- ObjCFieldLifetimeErrReported = true;
- }
} else if (getLangOpts().ObjC &&
getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
@@ -15943,14 +16391,23 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>()) {
QualType FT = FD->getType();
- if (FT.isNonTrivialToPrimitiveDefaultInitialize())
+ if (FT.isNonTrivialToPrimitiveDefaultInitialize()) {
Record->setNonTrivialToPrimitiveDefaultInitialize(true);
+ if (FT.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ Record->isUnion())
+ Record->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(true);
+ }
QualType::PrimitiveCopyKind PCK = FT.isNonTrivialToPrimitiveCopy();
- if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial)
+ if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial) {
Record->setNonTrivialToPrimitiveCopy(true);
+ if (FT.hasNonTrivialToPrimitiveCopyCUnion() || Record->isUnion())
+ Record->setHasNonTrivialToPrimitiveCopyCUnion(true);
+ }
if (FT.isDestructedType()) {
Record->setNonTrivialToPrimitiveDestroy(true);
Record->setParamDestroyedInCallee(true);
+ if (FT.hasNonTrivialToPrimitiveDestructCUnion() || Record->isUnion())
+ Record->setHasNonTrivialToPrimitiveDestructCUnion(true);
}
if (const auto *RT = FT->getAs<RecordType>()) {
@@ -16907,390 +17364,6 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
-static void checkModuleImportContext(Sema &S, Module *M,
- SourceLocation ImportLoc, DeclContext *DC,
- bool FromInclude = false) {
- SourceLocation ExternCLoc;
-
- if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
- switch (LSD->getLanguage()) {
- case LinkageSpecDecl::lang_c:
- if (ExternCLoc.isInvalid())
- ExternCLoc = LSD->getBeginLoc();
- break;
- case LinkageSpecDecl::lang_cxx:
- break;
- }
- DC = LSD->getParent();
- }
-
- while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC))
- DC = DC->getParent();
-
- if (!isa<TranslationUnitDecl>(DC)) {
- S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M))
- ? diag::ext_module_import_not_at_top_level_noop
- : diag::err_module_import_not_at_top_level_fatal)
- << M->getFullModuleName() << DC;
- S.Diag(cast<Decl>(DC)->getBeginLoc(),
- diag::note_module_import_not_at_top_level)
- << DC;
- } else if (!M->IsExternC && ExternCLoc.isValid()) {
- S.Diag(ImportLoc, diag::ext_module_import_in_extern_c)
- << M->getFullModuleName();
- S.Diag(ExternCLoc, diag::note_extern_c_begins_here);
- }
-}
-
-Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
- SourceLocation ModuleLoc,
- ModuleDeclKind MDK,
- ModuleIdPath Path) {
- assert(getLangOpts().ModulesTS &&
- "should only have module decl in modules TS");
-
- // A module implementation unit requires that we are not compiling a module
- // of any kind. A module interface unit requires that we are not compiling a
- // module map.
- switch (getLangOpts().getCompilingModule()) {
- case LangOptions::CMK_None:
- // It's OK to compile a module interface as a normal translation unit.
- break;
-
- case LangOptions::CMK_ModuleInterface:
- if (MDK != ModuleDeclKind::Implementation)
- break;
-
- // We were asked to compile a module interface unit but this is a module
- // implementation unit. That indicates the 'export' is missing.
- Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
- << FixItHint::CreateInsertion(ModuleLoc, "export ");
- MDK = ModuleDeclKind::Interface;
- break;
-
- case LangOptions::CMK_ModuleMap:
- Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
- return nullptr;
-
- case LangOptions::CMK_HeaderModule:
- Diag(ModuleLoc, diag::err_module_decl_in_header_module);
- return nullptr;
- }
-
- assert(ModuleScopes.size() == 1 && "expected to be at global module scope");
-
- // FIXME: Most of this work should be done by the preprocessor rather than
- // here, in order to support macro import.
-
- // Only one module-declaration is permitted per source file.
- if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) {
- Diag(ModuleLoc, diag::err_module_redeclaration);
- Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
- diag::note_prev_module_declaration);
- return nullptr;
- }
-
- // Flatten the dots in a module name. Unlike Clang's hierarchical module map
- // modules, the dots here are just another character that can appear in a
- // module name.
- std::string ModuleName;
- for (auto &Piece : Path) {
- if (!ModuleName.empty())
- ModuleName += ".";
- ModuleName += Piece.first->getName();
- }
-
- // If a module name was explicitly specified on the command line, it must be
- // correct.
- if (!getLangOpts().CurrentModule.empty() &&
- getLangOpts().CurrentModule != ModuleName) {
- Diag(Path.front().second, diag::err_current_module_name_mismatch)
- << SourceRange(Path.front().second, Path.back().second)
- << getLangOpts().CurrentModule;
- return nullptr;
- }
- const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName;
-
- auto &Map = PP.getHeaderSearchInfo().getModuleMap();
- Module *Mod;
-
- switch (MDK) {
- case ModuleDeclKind::Interface: {
- // We can't have parsed or imported a definition of this module or parsed a
- // module map defining it already.
- if (auto *M = Map.findModule(ModuleName)) {
- Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
- if (M->DefinitionLoc.isValid())
- Diag(M->DefinitionLoc, diag::note_prev_module_definition);
- else if (const auto *FE = M->getASTFile())
- Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
- << FE->getName();
- Mod = M;
- break;
- }
-
- // Create a Module for the module that we're defining.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- ModuleScopes.front().Module);
- assert(Mod && "module creation should not fail");
- break;
- }
-
- case ModuleDeclKind::Partition:
- // FIXME: Check we are in a submodule of the named module.
- return nullptr;
-
- case ModuleDeclKind::Implementation:
- std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
- PP.getIdentifierInfo(ModuleName), Path[0].second);
- Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
- Module::AllVisible,
- /*IsIncludeDirective=*/false);
- if (!Mod) {
- Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
- // Create an empty module interface unit for error recovery.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- ModuleScopes.front().Module);
- }
- break;
- }
-
- // Switch from the global module to the named module.
- ModuleScopes.back().Module = Mod;
- ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
- VisibleModules.setVisible(Mod, ModuleLoc);
-
- // From now on, we have an owning module for all declarations we see.
- // However, those declarations are module-private unless explicitly
- // exported.
- auto *TU = Context.getTranslationUnitDecl();
- TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
- TU->setLocalOwningModule(Mod);
-
- // FIXME: Create a ModuleDecl.
- return nullptr;
-}
-
-DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
- SourceLocation ImportLoc,
- ModuleIdPath Path) {
- // Flatten the module path for a Modules TS module name.
- std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
- if (getLangOpts().ModulesTS) {
- std::string ModuleName;
- for (auto &Piece : Path) {
- if (!ModuleName.empty())
- ModuleName += ".";
- ModuleName += Piece.first->getName();
- }
- ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second};
- Path = ModuleIdPath(ModuleNameLoc);
- }
-
- Module *Mod =
- getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
- /*IsIncludeDirective=*/false);
- if (!Mod)
- return true;
-
- VisibleModules.setVisible(Mod, ImportLoc);
-
- checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
-
- // FIXME: we should support importing a submodule within a different submodule
- // of the same top-level module. Until we do, make it an error rather than
- // silently ignoring the import.
- // Import-from-implementation is valid in the Modules TS. FIXME: Should we
- // warn on a redundant import of the current module?
- if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
- (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS))
- Diag(ImportLoc, getLangOpts().isCompilingModule()
- ? diag::err_module_self_import
- : diag::err_module_import_in_implementation)
- << Mod->getFullModuleName() << getLangOpts().CurrentModule;
-
- SmallVector<SourceLocation, 2> IdentifierLocs;
- Module *ModCheck = Mod;
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- // If we've run out of module parents, just drop the remaining identifiers.
- // We need the length to be consistent.
- if (!ModCheck)
- break;
- ModCheck = ModCheck->Parent;
-
- IdentifierLocs.push_back(Path[I].second);
- }
-
- ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc,
- Mod, IdentifierLocs);
- if (!ModuleScopes.empty())
- Context.addModuleInitializer(ModuleScopes.back().Module, Import);
- CurContext->addDecl(Import);
-
- // Re-export the module if needed.
- if (Import->isExported() &&
- !ModuleScopes.empty() && ModuleScopes.back().ModuleInterface)
- getCurrentModule()->Exports.emplace_back(Mod, false);
-
- return Import;
-}
-
-void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
- checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
- BuildModuleInclude(DirectiveLoc, Mod);
-}
-
-void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
- // Determine whether we're in the #include buffer for a module. The #includes
- // in that buffer do not qualify as module imports; they're just an
- // implementation detail of us building the module.
- //
- // FIXME: Should we even get ActOnModuleInclude calls for those?
- bool IsInModuleIncludes =
- TUKind == TU_Module &&
- getSourceManager().isWrittenInMainFile(DirectiveLoc);
-
- bool ShouldAddImport = !IsInModuleIncludes;
-
- // If this module import was due to an inclusion directive, create an
- // implicit import declaration to capture it in the AST.
- if (ShouldAddImport) {
- TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
- ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
- DirectiveLoc, Mod,
- DirectiveLoc);
- if (!ModuleScopes.empty())
- Context.addModuleInitializer(ModuleScopes.back().Module, ImportD);
- TU->addDecl(ImportD);
- Consumer.HandleImplicitImportDecl(ImportD);
- }
-
- getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc);
- VisibleModules.setVisible(Mod, DirectiveLoc);
-}
-
-void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
- checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
-
- ModuleScopes.push_back({});
- ModuleScopes.back().Module = Mod;
- if (getLangOpts().ModulesLocalVisibility)
- ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
-
- VisibleModules.setVisible(Mod, DirectiveLoc);
-
- // The enclosing context is now part of this module.
- // FIXME: Consider creating a child DeclContext to hold the entities
- // lexically within the module.
- if (getLangOpts().trackLocalOwningModule()) {
- for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
- cast<Decl>(DC)->setModuleOwnershipKind(
- getLangOpts().ModulesLocalVisibility
- ? Decl::ModuleOwnershipKind::VisibleWhenImported
- : Decl::ModuleOwnershipKind::Visible);
- cast<Decl>(DC)->setLocalOwningModule(Mod);
- }
- }
-}
-
-void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
- if (getLangOpts().ModulesLocalVisibility) {
- VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules);
- // Leaving a module hides namespace names, so our visible namespace cache
- // is now out of date.
- VisibleNamespaceCache.clear();
- }
-
- assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod &&
- "left the wrong module scope");
- ModuleScopes.pop_back();
-
- // We got to the end of processing a local module. Create an
- // ImportDecl as we would for an imported module.
- FileID File = getSourceManager().getFileID(EomLoc);
- SourceLocation DirectiveLoc;
- if (EomLoc == getSourceManager().getLocForEndOfFile(File)) {
- // We reached the end of a #included module header. Use the #include loc.
- assert(File != getSourceManager().getMainFileID() &&
- "end of submodule in main source file");
- DirectiveLoc = getSourceManager().getIncludeLoc(File);
- } else {
- // We reached an EOM pragma. Use the pragma location.
- DirectiveLoc = EomLoc;
- }
- BuildModuleInclude(DirectiveLoc, Mod);
-
- // Any further declarations are in whatever module we returned to.
- if (getLangOpts().trackLocalOwningModule()) {
- // The parser guarantees that this is the same context that we entered
- // the module within.
- for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
- cast<Decl>(DC)->setLocalOwningModule(getCurrentModule());
- if (!getCurrentModule())
- cast<Decl>(DC)->setModuleOwnershipKind(
- Decl::ModuleOwnershipKind::Unowned);
- }
- }
-}
-
-void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
- Module *Mod) {
- // Bail if we're not allowed to implicitly import a module here.
- if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery ||
- VisibleModules.isVisible(Mod))
- return;
-
- // Create the implicit import declaration.
- TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
- ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
- Loc, Mod, Loc);
- TU->addDecl(ImportD);
- Consumer.HandleImplicitImportDecl(ImportD);
-
- // Make the module visible.
- getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc);
- VisibleModules.setVisible(Mod, Loc);
-}
-
-/// We have parsed the start of an export declaration, including the '{'
-/// (if present).
-Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
- SourceLocation LBraceLoc) {
- ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
-
- // C++ Modules TS draft:
- // An export-declaration shall appear in the purview of a module other than
- // the global module.
- if (ModuleScopes.empty() || !ModuleScopes.back().ModuleInterface)
- Diag(ExportLoc, diag::err_export_not_in_module_interface);
-
- // An export-declaration [...] shall not contain more than one
- // export keyword.
- //
- // The intent here is that an export-declaration cannot appear within another
- // export-declaration.
- if (D->isExported())
- Diag(ExportLoc, diag::err_export_within_export);
-
- CurContext->addDecl(D);
- PushDeclContext(S, D);
- D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported);
- return D;
-}
-
-/// Complete the definition of an export declaration.
-Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
- auto *ED = cast<ExportDecl>(D);
- if (RBraceLoc.isValid())
- ED->setRBraceLoc(RBraceLoc);
-
- // FIXME: Diagnose export of internal-linkage declaration (including
- // anonymous namespace).
-
- PopDeclContext();
- return D;
-}
-
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
IdentifierInfo* AliasName,
SourceLocation PragmaLoc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 0e10804a2ec7..ee06f8ae5114 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1,9 +1,8 @@
//===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -246,11 +245,11 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
!Expr->isIntegerConstantExpr(I, S.Context)) {
if (Idx != UINT_MAX)
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
- << AI << Idx << AANT_ArgumentIntegerConstant
+ << &AI << Idx << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
else
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type)
- << AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
+ << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
return false;
}
@@ -262,7 +261,7 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
if (StrictlyUnsigned && I.isSigned() && I.isNegative()) {
S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer)
- << AI << /*non-negative*/ 1;
+ << &AI << /*non-negative*/ 1;
return false;
}
@@ -717,7 +716,8 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
+ S.Diag(AL.getLoc(),
+ diag::err_attribute_argument_out_of_bounds_extra_info)
<< AL << Idx + 1 << NumParams;
continue;
}
@@ -900,7 +900,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const Expr *SizeExpr = AL.getArgAsExpr(0);
int SizeArgNoVal;
// Parameter indices are 1-indexed, hence Index=1
- if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Index=*/1))
+ if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Idx=*/1))
return;
if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0))
return;
@@ -911,7 +911,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const Expr *NumberExpr = AL.getArgAsExpr(1);
int Val;
// Parameter indices are 1-based, hence Index=2
- if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Index=*/2))
+ if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Idx=*/2))
return;
if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1))
return;
@@ -1119,7 +1119,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// __builtin_object_size. So, it has the same constraints as that second
// argument; namely, it must be in the range [0, 3].
if (Type > 3) {
- S.Diag(E->getBeginLoc(), diag::err_attribute_argument_outof_range)
+ S.Diag(E->getBeginLoc(), diag::err_attribute_argument_out_of_range)
<< AL << 0 << 3 << E->getSourceRange();
return;
}
@@ -1673,7 +1673,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
ParamIdx Idx;
const auto *FuncDecl = cast<FunctionDecl>(D);
if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr,
- /*AttrArgNo=*/1, ParamExpr, Idx))
+ /*AttrArgNum=*/1, ParamExpr, Idx))
return;
QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
@@ -2284,18 +2284,11 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
return false;
}
-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) {
+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, int Priority, unsigned AttrSpellingListIndex) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
@@ -2329,16 +2322,15 @@ 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->isImplicit() && Implicit) {
+ // has a lower priority use the existing one and discard the new
+ // attribute.
+ if (OldAA->getPriority() < Priority)
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 (!Implicit && OldAA->isImplicit()) {
+ // If there is an existing attribute for this platform that has a higher
+ // priority than the new attribute then erase the old one and continue
+ // processing the attributes.
+ if (OldAA->getPriority() > Priority) {
Attrs.erase(Attrs.begin() + i);
--e;
continue;
@@ -2437,11 +2429,10 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
MergedDeprecated, MergedObsoleted) &&
!OverrideOrImpl) {
- auto *Avail = ::new (Context) AvailabilityAttr(Range, Context, Platform,
- Introduced, Deprecated,
- Obsoleted, IsUnavailable, Message,
- IsStrict, Replacement,
- AttrSpellingListIndex);
+ auto *Avail = ::new (Context)
+ AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated,
+ Obsoleted, IsUnavailable, Message, IsStrict,
+ Replacement, Priority, AttrSpellingListIndex);
Avail->setImplicit(Implicit);
return Avail;
}
@@ -2484,15 +2475,13 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II,
- false/*Implicit*/,
- Introduced.Version,
- Deprecated.Version,
- Obsoleted.Version,
- IsUnavailable, Str,
- IsStrict, Replacement,
- Sema::AMK_None,
- Index);
+ int PriorityModifier = AL.isPragmaClangAttribute()
+ ? Sema::AP_PragmaClangAttribute
+ : Sema::AP_Explicit;
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
+ ND, AL.getRange(), II, false /*Implicit*/, Introduced.Version,
+ Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
+ Replacement, Sema::AMK_None, PriorityModifier, Index);
if (NewAttr)
D->addAttr(NewAttr);
@@ -2519,6 +2508,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
else
return VersionTuple(NewMajor, Version.getMinor().getValue());
}
+ return VersionTuple(NewMajor);
}
return VersionTuple(2, 0);
@@ -2528,18 +2518,11 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version);
auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND,
- AL.getRange(),
- NewII,
- true/*Implicit*/,
- NewIntroduced,
- NewDeprecated,
- NewObsoleted,
- IsUnavailable, Str,
- IsStrict,
- Replacement,
- Sema::AMK_None,
- Index);
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
+ ND, AL.getRange(), NewII, true /*Implicit*/, NewIntroduced,
+ NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict,
+ Replacement, Sema::AMK_None,
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2553,20 +2536,13 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
NewII = &S.Context.Idents.get("tvos_app_extension");
if (NewII) {
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND,
- AL.getRange(),
- NewII,
- true/*Implicit*/,
- Introduced.Version,
- Deprecated.Version,
- Obsoleted.Version,
- IsUnavailable, Str,
- IsStrict,
- Replacement,
- Sema::AMK_None,
- Index);
- if (NewAttr)
- D->addAttr(NewAttr);
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
+ ND, AL.getRange(), NewII, true /*Implicit*/, Introduced.Version,
+ Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
+ Replacement, Sema::AMK_None,
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index);
+ if (NewAttr)
+ D->addAttr(NewAttr);
}
}
}
@@ -3035,13 +3011,18 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
-static bool checkCodeSegName(Sema&S, SourceLocation LiteralLoc, StringRef CodeSegName) {
- std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName);
+// This is used for `__declspec(code_seg("segname"))` on a decl.
+// `#pragma code_seg("segname")` uses checkSectionName() instead.
+static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
+ StringRef CodeSegName) {
+ std::string Error =
+ S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName);
if (!Error.empty()) {
- S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
- << 0 /*'code-seg'*/;
+ S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
+ << Error << 0 /*'code-seg'*/;
return false;
}
+
return true;
}
@@ -3325,7 +3306,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (prioritynum < 101 || prioritynum > 65535) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range)
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
<< E->getSourceRange() << AL << 101 << 65535;
AL.setInvalid();
return;
@@ -3480,6 +3461,146 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
+/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes.
+static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // The index that identifies the callback callee is mandatory.
+ if (AL.getNumArgs() == 0) {
+ S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee)
+ << AL.getRange();
+ return;
+ }
+
+ bool HasImplicitThisParam = isInstanceMethod(D);
+ int32_t NumArgs = getFunctionOrMethodNumParams(D);
+
+ FunctionDecl *FD = D->getAsFunction();
+ assert(FD && "Expected a function declaration!");
+
+ llvm::StringMap<int> NameIdxMapping;
+ NameIdxMapping["__"] = -1;
+
+ NameIdxMapping["this"] = 0;
+
+ int Idx = 1;
+ for (const ParmVarDecl *PVD : FD->parameters())
+ NameIdxMapping[PVD->getName()] = Idx++;
+
+ auto UnknownName = NameIdxMapping.end();
+
+ SmallVector<int, 8> EncodingIndices;
+ for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) {
+ SourceRange SR;
+ int32_t ArgIdx;
+
+ if (AL.isArgIdent(I)) {
+ IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
+ auto It = NameIdxMapping.find(IdLoc->Ident->getName());
+ if (It == UnknownName) {
+ S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)
+ << IdLoc->Ident << IdLoc->Loc;
+ return;
+ }
+
+ SR = SourceRange(IdLoc->Loc);
+ ArgIdx = It->second;
+ } else if (AL.isArgExpr(I)) {
+ Expr *IdxExpr = AL.getArgAsExpr(I);
+
+ // If the expression is not parseable as an int32_t we have a problem.
+ if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
+ false)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << (I + 1) << IdxExpr->getSourceRange();
+ return;
+ }
+
+ // Check oob, excluding the special values, 0 and -1.
+ if (ArgIdx < -1 || ArgIdx > NumArgs) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << (I + 1) << IdxExpr->getSourceRange();
+ return;
+ }
+
+ SR = IdxExpr->getSourceRange();
+ } else {
+ llvm_unreachable("Unexpected ParsedAttr argument type!");
+ }
+
+ if (ArgIdx == 0 && !HasImplicitThisParam) {
+ S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available)
+ << (I + 1) << SR;
+ return;
+ }
+
+ // Adjust for the case we do not have an implicit "this" parameter. In this
+ // case we decrease all positive values by 1 to get LLVM argument indices.
+ if (!HasImplicitThisParam && ArgIdx > 0)
+ ArgIdx -= 1;
+
+ EncodingIndices.push_back(ArgIdx);
+ }
+
+ int CalleeIdx = EncodingIndices.front();
+ // Check if the callee index is proper, thus not "this" and not "unknown".
+ // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam"
+ // is false and positive if "HasImplicitThisParam" is true.
+ if (CalleeIdx < (int)HasImplicitThisParam) {
+ S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee)
+ << AL.getRange();
+ return;
+ }
+
+ // Get the callee type, note the index adjustment as the AST doesn't contain
+ // the this type (which the callee cannot reference anyway!).
+ const Type *CalleeType =
+ getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam)
+ .getTypePtr();
+ if (!CalleeType || !CalleeType->isFunctionPointerType()) {
+ S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
+ << AL.getRange();
+ return;
+ }
+
+ const Type *CalleeFnType =
+ CalleeType->getPointeeType()->getUnqualifiedDesugaredType();
+
+ // TODO: Check the type of the callee arguments.
+
+ const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType);
+ if (!CalleeFnProtoType) {
+ S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
+ << AL.getRange();
+ return;
+ }
+
+ if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) {
+ S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << AL << (unsigned)(EncodingIndices.size() - 1);
+ return;
+ }
+
+ if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {
+ S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << AL << (unsigned)(EncodingIndices.size() - 1);
+ return;
+ }
+
+ if (CalleeFnProtoType->isVariadic()) {
+ S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange();
+ return;
+ }
+
+ // Do not allow multiple callback attributes.
+ if (D->hasAttr<CallbackAttr>()) {
+ S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange();
+ return;
+ }
+
+ D->addAttr(::new (S.Context) CallbackAttr(
+ AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(),
+ AL.getAttributeSpellingListIndex()));
+}
+
static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Try to find the underlying union declaration.
RecordDecl *RD = nullptr;
@@ -4157,6 +4278,15 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex);
}
+NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
+ Decl *D, const NoSpeculativeLoadHardeningAttr &AL) {
+ if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
+ return nullptr;
+
+ return ::new (Context) NoSpeculativeLoadHardeningAttr(
+ AL.getRange(), Context, AL.getSpellingListIndex());
+}
+
OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex) {
if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
@@ -4177,6 +4307,15 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
AttrSpellingListIndex);
}
+SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
+ Decl *D, const SpeculativeLoadHardeningAttr &AL) {
+ if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
+ return nullptr;
+
+ return ::new (Context) SpeculativeLoadHardeningAttr(
+ AL.getRange(), Context, AL.getSpellingListIndex());
+}
+
static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
return;
@@ -4482,11 +4621,56 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
default: llvm_unreachable("unexpected attribute kind");
}
+ TargetInfo::CallingConvCheckResult A = TargetInfo::CCCR_OK;
const TargetInfo &TI = Context.getTargetInfo();
- TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
- if (A != TargetInfo::CCCR_OK) {
- if (A == TargetInfo::CCCR_Warning)
- Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs;
+ // CUDA functions may have host and/or device attributes which indicate
+ // their targeted execution environment, therefore the calling convention
+ // of functions in CUDA should be checked against the target deduced based
+ // on their host/device attributes.
+ if (LangOpts.CUDA) {
+ auto *Aux = Context.getAuxTargetInfo();
+ auto CudaTarget = IdentifyCUDATarget(FD);
+ bool CheckHost = false, CheckDevice = false;
+ switch (CudaTarget) {
+ case CFT_HostDevice:
+ CheckHost = true;
+ CheckDevice = true;
+ break;
+ case CFT_Host:
+ CheckHost = true;
+ break;
+ case CFT_Device:
+ case CFT_Global:
+ CheckDevice = true;
+ break;
+ case CFT_InvalidTarget:
+ llvm_unreachable("unexpected cuda target");
+ }
+ auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI;
+ auto *DeviceTI = LangOpts.CUDAIsDevice ? &TI : Aux;
+ if (CheckHost && HostTI)
+ A = HostTI->checkCallingConvention(CC);
+ if (A == TargetInfo::CCCR_OK && CheckDevice && DeviceTI)
+ A = DeviceTI->checkCallingConvention(CC);
+ } else {
+ A = TI.checkCallingConvention(CC);
+ }
+
+ switch (A) {
+ case TargetInfo::CCCR_OK:
+ break;
+
+ case TargetInfo::CCCR_Ignore:
+ // Treat an ignored convention as if it was an explicit C calling convention
+ // attribute. For example, __stdcall on Win x64 functions as __cdecl, so
+ // that command line flags that change the default convention to
+ // __vectorcall don't affect declarations marked __stdcall.
+ CC = CC_C;
+ break;
+
+ case TargetInfo::CCCR_Warning: {
+ Diag(Attrs.getLoc(), diag::warn_cconv_unsupported)
+ << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
// This convention is not valid for the target. Use the default function or
// method calling convention.
@@ -4496,6 +4680,8 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
IsVariadic = FD->isVariadic();
}
CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
+ break;
+ }
}
Attrs.setProcessingCache((unsigned) CC);
@@ -5116,11 +5302,22 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
const ParsedAttr &AL) {
+ DeclContext *Ctx = D->getDeclContext();
+
+ // This attribute can only be applied to methods in interfaces or class
+ // extensions.
+ if (!isa<ObjCInterfaceDecl>(Ctx) &&
+ !(isa<ObjCCategoryDecl>(Ctx) &&
+ cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) {
+ S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
+ return;
+ }
+
ObjCInterfaceDecl *IFace;
- if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
+ if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx))
IFace = CatDecl->getClassInterface();
else
- IFace = cast<ObjCInterfaceDecl>(D->getDeclContext());
+ IFace = cast<ObjCInterfaceDecl>(Ctx);
if (!IFace)
return;
@@ -5377,6 +5574,27 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // MSP430 'interrupt' attribute is applied to
+ // a function with no parameters and void return type.
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'interrupt'" << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
+ S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MSP430*/ 1 << 0;
+ return;
+ }
+
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MSP430*/ 1 << 1;
+ return;
+ }
+
+ // The attribute takes one integer argument.
if (!checkAttributeNumArgs(S, AL, 1))
return;
@@ -5386,8 +5604,6 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- // FIXME: Check for decl - it should be void ()(void).
-
Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
llvm::APSInt NumParams(32);
if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
@@ -5396,9 +5612,9 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< NumParamsExpr->getSourceRange();
return;
}
-
+ // The argument should be in range 0..63.
unsigned Num = NumParams.getLimitedValue(255);
- if ((Num & 1) || Num > 30) {
+ if (Num > 63) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
<< AL << (int)NumParams.getSExtValue()
<< NumParamsExpr->getSourceRange();
@@ -5442,14 +5658,14 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute)
- << 0;
+ S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MIPS*/ 0 << 0;
return;
}
if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute)
- << 1;
+ S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*MIPS*/ 0 << 1;
return;
}
@@ -5558,6 +5774,51 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
}
+static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'import_module'" << ExpectedFunction;
+ return;
+ }
+
+ auto *FD = cast<FunctionDecl>(D);
+ if (FD->isThisDeclarationADefinition()) {
+ S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr(
+ AL.getRange(), S.Context, Str,
+ AL.getAttributeSpellingListIndex()));
+}
+
+static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'import_name'" << ExpectedFunction;
+ return;
+ }
+
+ auto *FD = cast<FunctionDecl>(D);
+ if (FD->isThisDeclarationADefinition()) {
+ S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(
+ AL.getRange(), S.Context, Str,
+ AL.getAttributeSpellingListIndex()));
+}
static void handleRISCVInterruptAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
@@ -5596,12 +5857,14 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D,
}
if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 0;
+ S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*RISC-V*/ 2 << 0;
return;
}
if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 1;
+ S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
+ << /*RISC-V*/ 2 << 1;
return;
}
@@ -5643,57 +5906,115 @@ static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
-static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
+static bool
+checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
+ const AMDGPUFlatWorkGroupSizeAttr &Attr) {
+ // Accept template arguments for now as they depend on something else.
+ // We'll get to check them when they eventually get instantiated.
+ if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
+ return false;
+
uint32_t Min = 0;
- Expr *MinExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, MinExpr, Min))
- return;
+ if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
+ return true;
uint32_t Max = 0;
- Expr *MaxExpr = AL.getArgAsExpr(1);
- if (!checkUInt32Argument(S, AL, MaxExpr, Max))
- return;
+ if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
+ return true;
if (Min == 0 && Max != 0) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0;
- return;
+ S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
+ << &Attr << 0;
+ return true;
}
if (Min > Max) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
- return;
+ S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
+ << &Attr << 1;
+ return true;
}
- D->addAttr(::new (S.Context)
- AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max,
- AL.getAttributeSpellingListIndex()));
+ return false;
}
-static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t Min = 0;
- Expr *MinExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, MinExpr, Min))
+void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D,
+ Expr *MinExpr, Expr *MaxExpr,
+ unsigned SpellingListIndex) {
+ AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
+ SpellingListIndex);
+
+ if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;
+ D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr(
+ AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex));
+}
+
+static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ Expr *MinExpr = AL.getArgAsExpr(0);
+ Expr *MaxExpr = AL.getArgAsExpr(1);
+
+ S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr,
+ AL.getAttributeSpellingListIndex());
+}
+
+static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
+ Expr *MaxExpr,
+ const AMDGPUWavesPerEUAttr &Attr) {
+ if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
+ (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
+ return true;
+
+ // Accept template arguments for now as they depend on something else.
+ // We'll get to check them when they eventually get instantiated.
+ if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
+ return false;
+
+ uint32_t Min = 0;
+ if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
+ return true;
+
uint32_t Max = 0;
- if (AL.getNumArgs() == 2) {
- Expr *MaxExpr = AL.getArgAsExpr(1);
- if (!checkUInt32Argument(S, AL, MaxExpr, Max))
- return;
- }
+ if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
+ return true;
if (Min == 0 && Max != 0) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0;
- return;
+ S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
+ << &Attr << 0;
+ return true;
}
if (Max != 0 && Min > Max) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
- return;
+ S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
+ << &Attr << 1;
+ return true;
}
- D->addAttr(::new (S.Context)
- AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max,
- AL.getAttributeSpellingListIndex()));
+ return false;
+}
+
+void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D,
+ Expr *MinExpr, Expr *MaxExpr,
+ unsigned SpellingListIndex) {
+ AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
+ SpellingListIndex);
+
+ if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
+ return;
+
+ D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr,
+ MaxExpr, SpellingListIndex));
+}
+
+static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!checkAttributeAtLeastNumArgs(S, AL, 1) ||
+ !checkAttributeAtMostNumArgs(S, AL, 2))
+ return;
+
+ Expr *MinExpr = AL.getArgAsExpr(0);
+ Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
+
+ S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr,
+ AL.getAttributeSpellingListIndex());
}
static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6001,7 +6322,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc))
return;
- if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0)
+ if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) ==
+ SanitizerMask())
S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
else if (isGlobalVar(D) && SanitizerName != "address")
S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
@@ -6026,9 +6348,21 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
if (isGlobalVar(D) && SanitizerName != "address")
S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
<< AL << ExpectedFunction;
- D->addAttr(::new (S.Context)
- NoSanitizeAttr(AL.getRange(), S.Context, &SanitizerName, 1,
- AL.getAttributeSpellingListIndex()));
+
+ // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a
+ // NoSanitizeAttr object; but we need to calculate the correct spelling list
+ // index rather than incorrectly assume the index for NoSanitizeSpecificAttr
+ // has the same spellings as the index for NoSanitizeAttr. We don't have a
+ // general way to "translate" between the two, so this hack attempts to work
+ // around the issue with hard-coded indicies. This is critical for calling
+ // getSpelling() or prettyPrint() on the resulting semantic attribute object
+ // without failing assertions.
+ unsigned TranslatedSpellingIndex = 0;
+ if (AL.isC2xAttribute() || AL.isCXX11Attribute())
+ TranslatedSpellingIndex = 1;
+
+ D->addAttr(::new (S.Context) NoSanitizeAttr(
+ AL.getRange(), S.Context, &SanitizerName, 1, TranslatedSpellingIndex));
}
static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6114,7 +6448,9 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
if (AL.getName()->getName().find("read_write") != StringRef::npos) {
- if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) {
+ if ((!S.getLangOpts().OpenCLCPlusPlus &&
+ S.getLangOpts().OpenCLVersion < 200) ||
+ DeclTy->isPipeType()) {
S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write)
<< AL << PDecl->getType() << DeclTy->isImageType();
D->setInvalidDecl(true);
@@ -6221,6 +6557,42 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D,
handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
}
+static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // Check that the return type is a `typedef int kern_return_t` or a typedef
+ // around it, because otherwise MIG convention checks make no sense.
+ // BlockDecl doesn't store a return type, so it's annoying to check,
+ // so let's skip it for now.
+ if (!isa<BlockDecl>(D)) {
+ QualType T = getFunctionOrMethodResultType(D);
+ bool IsKernReturnT = false;
+ while (const auto *TT = T->getAs<TypedefType>()) {
+ IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t");
+ T = TT->desugar();
+ }
+ if (!IsKernReturnT || T.getCanonicalType() != S.getASTContext().IntTy) {
+ S.Diag(D->getBeginLoc(),
+ diag::warn_mig_server_routine_does_not_return_kern_return_t);
+ return;
+ }
+ }
+
+ handleSimpleAttribute<MIGServerRoutineAttr>(S, D, AL);
+}
+
+static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // Warn if the return type is not a pointer or reference type.
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ QualType RetTy = FD->getReturnType();
+ if (!RetTy->isPointerType() && !RetTy->isReferenceType()) {
+ S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer)
+ << AL.getRange() << RetTy;
+ return;
+ }
+ }
+
+ handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -6311,6 +6683,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AVRSignal:
handleAVRSignalAttr(S, D, AL);
break;
+ case ParsedAttr::AT_WebAssemblyImportModule:
+ handleWebAssemblyImportModuleAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_WebAssemblyImportName:
+ handleWebAssemblyImportNameAttr(S, D, AL);
+ break;
case ParsedAttr::AT_IBAction:
handleSimpleAttribute<IBActionAttr>(S, D, AL);
break;
@@ -6414,6 +6792,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_FormatArg:
handleFormatArgAttr(S, D, AL);
break;
+ case ParsedAttr::AT_Callback:
+ handleCallbackAttr(S, D, AL);
+ break;
case ParsedAttr::AT_CUDAGlobal:
handleGlobalAttr(S, D, AL);
break;
@@ -6424,6 +6805,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_CUDAHost:
handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_HIPPinnedShadow:
+ handleSimpleAttributeWithExclusions<HIPPinnedShadowAttr, CUDADeviceAttr,
+ CUDAConstantAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_GNUInline:
handleGNUInlineAttr(S, D, AL);
break;
@@ -6451,6 +6836,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_NoSplitStack:
handleSimpleAttribute<NoSplitStackAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_NoUniqueAddress:
+ handleSimpleAttribute<NoUniqueAddressAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_NonNull:
if (auto *PVD = dyn_cast<ParmVarDecl>(D))
handleNonNullAttrParameter(S, PVD, AL);
@@ -6491,7 +6879,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleNoCfCheckAttr(S, D, AL);
break;
case ParsedAttr::AT_NoThrow:
- handleSimpleAttribute<NoThrowAttr>(S, D, AL);
+ if (!AL.isUsedAsTypeAttr())
+ handleSimpleAttribute<NoThrowAttr>(S, D, AL);
break;
case ParsedAttr::AT_CUDAShared:
handleSharedAttr(S, D, AL);
@@ -6599,7 +6988,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSectionAttr(S, D, AL);
break;
case ParsedAttr::AT_SpeculativeLoadHardening:
- handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL);
+ handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr,
+ NoSpeculativeLoadHardeningAttr>(S, D,
+ AL);
+ break;
+ case ParsedAttr::AT_NoSpeculativeLoadHardening:
+ handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr,
+ SpeculativeLoadHardeningAttr>(S, D, AL);
break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
@@ -6619,9 +7014,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_ObjCRootClass:
handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_ObjCNonLazyClass:
+ handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_ObjCSubclassingRestricted:
handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_ObjCClassStub:
+ handleSimpleAttribute<ObjCClassStubAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_ObjCExplicitProtocolImpl:
handleObjCSuppresProtocolAttr(S, D, AL);
break;
@@ -6932,6 +7333,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_ObjCExternallyRetained:
handleObjCExternallyRetainedAttr(S, D, AL);
break;
+
+ case ParsedAttr::AT_MIGServerRoutine:
+ handleMIGServerRoutineAttr(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_MSAllocator:
+ handleMSAllocatorAttr(S, D, AL);
+ break;
}
}
@@ -6997,6 +7406,17 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
}
}
}
+
+ // Do this check after processing D's attributes because the attribute
+ // objc_method_family can change whether the given method is in the init
+ // family, and it can be applied after objc_designated_initializer. This is a
+ // bit of a hack, but we need it to be compatible with versions of clang that
+ // processed the attribute list in the wrong order.
+ if (D->hasAttr<ObjCDesignatedInitializerAttr>() &&
+ cast<ObjCMethodDecl>(D)->getMethodFamily() != OMF_init) {
+ Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
+ D->dropAttr<ObjCDesignatedInitializerAttr>();
+ }
}
// Helper for delayed processing TransparentUnion attribute.
@@ -7066,12 +7486,10 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
// FIXME: Mangling?
// FIXME: Is the qualifier info correct?
// FIXME: Is the DeclContext correct?
- NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
- Loc, Loc, DeclarationName(II),
- FD->getType(), FD->getTypeSourceInfo(),
- SC_None, false/*isInlineSpecified*/,
- FD->hasPrototype(),
- false/*isConstexprSpecified*/);
+ NewFD = FunctionDecl::Create(
+ FD->getASTContext(), FD->getDeclContext(), Loc, Loc,
+ DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None,
+ false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified);
NewD = NewFD;
if (FD->getQualifier())
@@ -7346,13 +7764,11 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
return true;
} else if (K == AR_Unavailable) {
// It is perfectly fine to refer to an 'unavailable' Objective-C method
- // when it's actually defined and is referenced from within the
- // @implementation itself. In this context, we interpret unavailable as a
- // form of access control.
+ // when it is referenced from within the @implementation itself. In this
+ // context, we interpret unavailable as a form of access control.
if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
- if (MD->getClassInterface() == Impl->getClassInterface() &&
- MD->isDefined())
+ if (MD->getClassInterface() == Impl->getClassInterface())
return true;
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 43b289d8d0de..9a6385f28319 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1,9 +1,8 @@
//===------ SemaDeclCXX.cpp - Semantic Analysis for C++ Declarations ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -63,7 +62,7 @@ namespace {
public:
CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
- : DefaultArg(defarg), S(s) {}
+ : DefaultArg(defarg), S(s) {}
bool VisitExpr(Expr *Node);
bool VisitDeclRefExpr(DeclRefExpr *DRE);
@@ -193,6 +192,7 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
// If this function has a basic noexcept, it doesn't affect the outcome.
case EST_BasicNoexcept:
case EST_NoexceptTrue:
+ case EST_NoThrow:
return;
// If we're still at noexcept(true) and there's a throw() callee,
// change to that specification.
@@ -638,9 +638,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// C++11 [dcl.constexpr]p1: If any declaration of a function or function
// template has a constexpr specifier then all its declarations shall
// contain the constexpr specifier.
- if (New->isConstexpr() != Old->isConstexpr()) {
+ if (New->getConstexprKind() != Old->getConstexprKind()) {
Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
- << New << New->isConstexpr();
+ << New << New->getConstexprKind() << Old->getConstexprKind();
Diag(Old->getLocation(), diag::note_previous_declaration);
Invalid = true;
} else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
@@ -658,14 +658,13 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = true;
}
- // FIXME: It's not clear what should happen if multiple declarations of a
- // deduction guide have different explicitness. For now at least we simply
- // reject any case where the explicitness changes.
- auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
- if (NewGuide && NewGuide->isExplicitSpecified() !=
- cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
- Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
- << NewGuide->isExplicitSpecified();
+ // C++17 [temp.deduct.guide]p3:
+ // Two deduction guide declarations in the same translation unit
+ // for the same class template shall not have equivalent
+ // parameter-declaration-clauses.
+ if (isa<CXXDeductionGuideDecl>(New) &&
+ !New->isFunctionTemplateSpecialization()) {
+ Diag(New->getLocation(), diag::err_deduction_guide_redeclared);
Diag(Old->getLocation(), diag::note_previous_declaration);
}
@@ -717,23 +716,34 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// The semantic context is always just the current context.
DeclContext *const DC = CurContext;
- // C++1z [dcl.dcl]/8:
+ // C++17 [dcl.dcl]/8:
// The decl-specifier-seq shall contain only the type-specifier auto
// and cv-qualifiers.
+ // C++2a [dcl.dcl]/8:
+ // If decl-specifier-seq contains any decl-specifier other than static,
+ // thread_local, auto, or cv-qualifiers, the program is ill-formed.
auto &DS = D.getDeclSpec();
{
SmallVector<StringRef, 8> BadSpecifiers;
SmallVector<SourceLocation, 8> BadSpecifierLocs;
+ SmallVector<StringRef, 8> CPlusPlus20Specifiers;
+ SmallVector<SourceLocation, 8> CPlusPlus20SpecifierLocs;
if (auto SCS = DS.getStorageClassSpec()) {
- BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
- BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
+ if (SCS == DeclSpec::SCS_static) {
+ CPlusPlus20Specifiers.push_back(DeclSpec::getSpecifierName(SCS));
+ CPlusPlus20SpecifierLocs.push_back(DS.getStorageClassSpecLoc());
+ } else {
+ BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
+ BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
+ }
}
if (auto TSCS = DS.getThreadStorageClassSpec()) {
- BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS));
- BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
+ CPlusPlus20Specifiers.push_back(DeclSpec::getSpecifierName(TSCS));
+ CPlusPlus20SpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
}
- if (DS.isConstexprSpecified()) {
- BadSpecifiers.push_back("constexpr");
+ if (DS.hasConstexprSpecifier()) {
+ BadSpecifiers.push_back(
+ DeclSpec::getSpecifierName(DS.getConstexprSpecifier()));
BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
}
if (DS.isInlineSpecified()) {
@@ -748,6 +758,16 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// them when building the underlying variable.
for (auto Loc : BadSpecifierLocs)
Err << SourceRange(Loc, Loc);
+ } else if (!CPlusPlus20Specifiers.empty()) {
+ auto &&Warn = Diag(CPlusPlus20SpecifierLocs.front(),
+ getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_decomp_decl_spec
+ : diag::ext_decomp_decl_spec);
+ Warn << (int)CPlusPlus20Specifiers.size()
+ << llvm::join(CPlusPlus20Specifiers.begin(),
+ CPlusPlus20Specifiers.end(), " ");
+ for (auto Loc : CPlusPlus20SpecifierLocs)
+ Warn << SourceRange(Loc, Loc);
}
// We can't recover from it being declared as a typedef.
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
@@ -1129,7 +1149,6 @@ static bool checkTupleLikeDecomposition(Sema &S,
}
}
}
- S.FilterAcceptableTemplateNames(MemberGet);
}
unsigned I = 0;
@@ -1160,7 +1179,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
if (E.isInvalid())
return true;
- E = S.ActOnCallExpr(nullptr, E.get(), Loc, None, Loc);
+ E = S.BuildCallExpr(nullptr, E.get(), Loc, None, Loc);
} else {
// Otherwise, the initializer is get<i-1>(e), where get is looked up
// in the associated namespaces.
@@ -1170,7 +1189,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
UnresolvedSetIterator(), UnresolvedSetIterator());
Expr *Arg = E.get();
- E = S.ActOnCallExpr(nullptr, Get, Loc, Arg, Loc);
+ E = S.BuildCallExpr(nullptr, Get, Loc, Arg, Loc);
}
if (E.isInvalid())
return true;
@@ -1301,6 +1320,10 @@ static DeclAccessPair findDecomposableBaseClass(Sema &S, SourceLocation Loc,
static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
ValueDecl *Src, QualType DecompType,
const CXXRecordDecl *OrigRD) {
+ if (S.RequireCompleteType(Src->getLocation(), DecompType,
+ diag::err_incomplete_type))
+ return true;
+
CXXCastPath BasePath;
DeclAccessPair BasePair =
findDecomposableBaseClass(S, Src->getLocation(), OrigRD, BasePath);
@@ -1559,10 +1582,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
- SemaRef.RequireLiteralType(ParamLoc, *i,
- diag::err_constexpr_non_literal_param,
- ArgIndex+1, PD->getSourceRange(),
- isa<CXXConstructorDecl>(FD)))
+ SemaRef.RequireLiteralType(
+ ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1,
+ PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
+ FD->isConsteval()))
return false;
}
return true;
@@ -1595,6 +1618,9 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
// The definition of a constexpr constructor shall satisfy the following
// constraints:
// - the class shall not have any virtual base classes;
+ //
+ // FIXME: This only applies to constructors, not arbitrary member
+ // functions.
const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
@@ -1611,28 +1637,33 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
// C++11 [dcl.constexpr]p3:
// The definition of a constexpr function shall satisfy the following
// constraints:
- // - it shall not be virtual;
+ // - it shall not be virtual; (removed in C++20)
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
- Method = Method->getCanonicalDecl();
- Diag(Method->getLocation(), diag::err_constexpr_virtual);
-
- // If it's not obvious why this function is virtual, find an overridden
- // function which uses the 'virtual' keyword.
- const CXXMethodDecl *WrittenVirtual = Method;
- while (!WrittenVirtual->isVirtualAsWritten())
- WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
- if (WrittenVirtual != Method)
- Diag(WrittenVirtual->getLocation(),
- diag::note_overridden_virtual_function);
- return false;
+ if (getLangOpts().CPlusPlus2a) {
+ Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
+ } else {
+ Method = Method->getCanonicalDecl();
+ Diag(Method->getLocation(), diag::err_constexpr_virtual);
+
+ // If it's not obvious why this function is virtual, find an overridden
+ // function which uses the 'virtual' keyword.
+ const CXXMethodDecl *WrittenVirtual = Method;
+ while (!WrittenVirtual->isVirtualAsWritten())
+ WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
+ if (WrittenVirtual != Method)
+ Diag(WrittenVirtual->getLocation(),
+ diag::note_overridden_virtual_function);
+ return false;
+ }
}
// - its return type shall be a literal type;
QualType RT = NewFD->getReturnType();
if (!RT->isDependentType() &&
RequireLiteralType(NewFD->getLocation(), RT,
- diag::err_constexpr_non_literal_return))
+ diag::err_constexpr_non_literal_return,
+ NewFD->isConsteval()))
return false;
}
@@ -1746,7 +1777,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
default:
SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl);
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
return false;
}
}
@@ -1931,7 +1962,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
}
SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl);
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
return false;
}
@@ -2053,7 +2084,8 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
Dcl->getReturnType()->isDependentType());
Diag(Dcl->getLocation(),
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
- : diag::err_constexpr_body_no_return);
+ : diag::err_constexpr_body_no_return)
+ << Dcl->isConsteval();
if (!OK)
return false;
} else if (ReturnStmts.size() > 1) {
@@ -3023,7 +3055,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
!isFunc);
- if (DS.isConstexprSpecified() && isInstField) {
+ if (DS.hasConstexprSpecifier() && isInstField) {
SemaDiagnosticBuilder B =
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member);
SourceLocation ConstexprLoc = DS.getConstexprSpecLoc();
@@ -3172,7 +3204,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// declared] with the same access [as the template].
if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(NonTemplateMember)) {
auto *TD = DG->getDeducedTemplate();
- if (AS != TD->getAccess()) {
+ // Access specifiers are only meaningful if both the template and the
+ // deduction guide are from the same scope.
+ if (AS != TD->getAccess() &&
+ TD->getDeclContext()->getRedeclContext()->Equals(
+ DG->getDeclContext()->getRedeclContext())) {
Diag(DG->getBeginLoc(), diag::err_deduction_guide_wrong_access);
Diag(TD->getBeginLoc(), diag::note_deduction_guide_template_access)
<< TD->getAccess();
@@ -3775,7 +3811,7 @@ namespace {
// Callback to only accept typo corrections that can be a valid C++ member
// intializer: either a non-static field member or a base class.
-class MemInitializerValidatorCCC : public CorrectionCandidateCallback {
+class MemInitializerValidatorCCC final : public CorrectionCandidateCallback {
public:
explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl)
: ClassDecl(ClassDecl) {}
@@ -3789,6 +3825,10 @@ public:
return false;
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<MemInitializerValidatorCCC>(*this);
+ }
+
private:
CXXRecordDecl *ClassDecl;
};
@@ -3871,6 +3911,8 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (TemplateTypeTy) {
BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
+ if (BaseType.isNull())
+ return true;
} else if (DS.getTypeSpecType() == TST_decltype) {
BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
} else if (DS.getTypeSpecType() == TST_decltype_auto) {
@@ -3918,11 +3960,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// If no results were found, try to correct typos.
TypoCorrection Corr;
+ MemInitializerValidatorCCC CCC(ClassDecl);
if (R.empty() && BaseType.isNull() &&
- (Corr = CorrectTypo(
- R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- llvm::make_unique<MemInitializerValidatorCCC>(ClassDecl),
- CTK_ErrorRecovery, ClassDecl))) {
+ (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
+ CCC, CTK_ErrorRecovery, ClassDecl))) {
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
@@ -5688,9 +5729,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
- // Ignore explicit dllexport on explicit class template instantiation declarations.
+ // Ignore explicit dllexport on explicit class template instantiation
+ // declarations, except in MinGW mode.
if (ClassExported && !ClassAttr->isInherited() &&
- TSK == TSK_ExplicitInstantiationDeclaration) {
+ TSK == TSK_ExplicitInstantiationDeclaration &&
+ !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
Class->dropAttr<DLLExportAttr>();
return;
}
@@ -5715,9 +5758,12 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
continue;
if (MD->isInlined()) {
- // MinGW does not import or export inline methods.
+ // MinGW does not import or export inline methods. But do it for
+ // template instantiations.
if (!Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())
+ !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() &&
+ TSK != TSK_ExplicitInstantiationDeclaration &&
+ TSK != TSK_ExplicitInstantiationDefinition)
continue;
// MSVC versions before 2015 don't export the move assignment operators
@@ -5886,9 +5932,6 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
if (D->isDependentType() || D->isInvalidDecl())
return false;
- if (D->hasAttr<TrivialABIAttr>())
- return true;
-
// Clang <= 4 used the pre-C++11 rule, which ignores move operations.
// The PS4 platform ABI follows the behavior of Clang 3.2.
if (CCK == TargetInfo::CCK_ClangABI4OrPS4)
@@ -5946,8 +5989,11 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
// Note: This permits small classes with nontrivial destructors to be
// passed in registers, which is non-conforming.
+ bool isAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
+ uint64_t TypeSize = isAArch64 ? 128 : 64;
+
if (CopyCtorIsTrivial &&
- S.getASTContext().getTypeSize(D->getTypeForDecl()) <= 64)
+ S.getASTContext().getTypeSize(D->getTypeForDecl()) <= TypeSize)
return true;
return false;
}
@@ -6082,9 +6128,60 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (HasTrivialABI)
Record->setHasTrivialSpecialMemberForCall();
+ auto CompleteMemberFunction = [&](CXXMethodDecl *M) {
+ // Check whether the explicitly-defaulted special members are valid.
+ if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
+ CheckExplicitlyDefaultedSpecialMember(M);
+
+ // 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()) {
+ if (CSM != CXXInvalid) {
+ M->setTrivial(SpecialMemberIsTrivial(M, CSM));
+ // Inform the class that we've finished declaring this member.
+ Record->finishedDefaultedOrDeletedMember(M);
+ M->setTrivialForCall(
+ HasTrivialABI ||
+ SpecialMemberIsTrivial(M, CSM, TAH_ConsiderTrivialABI));
+ Record->setTrivialForCallFlags(M);
+ }
+ }
+
+ // Set triviality for the purpose of calls if this is a user-provided
+ // copy/move constructor or destructor.
+ if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor ||
+ CSM == CXXDestructor) && M->isUserProvided()) {
+ M->setTrivialForCall(HasTrivialABI);
+ Record->setTrivialForCallFlags(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);
+ }
+ }
+ };
+
bool HasMethodWithOverrideControl = false,
HasOverridingMethodWithoutOverrideControl = false;
if (!Record->isDependentType()) {
+ // Check the destructor before any other member function. We need to
+ // determine whether it's trivial in order to determine whether the claas
+ // type is a literal type, which is a prerequisite for determining whether
+ // other special member functions are valid and whether they're implicitly
+ // 'constexpr'.
+ if (CXXDestructorDecl *Dtor = Record->getDestructor())
+ CompleteMemberFunction(Dtor);
+
for (auto *M : Record->methods()) {
// See if a method overloads virtual methods in a base
// class without overriding any.
@@ -6094,46 +6191,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
HasMethodWithOverrideControl = true;
else if (M->size_overridden_methods() > 0)
HasOverridingMethodWithoutOverrideControl = true;
- // Check whether the explicitly-defaulted special members are valid.
- if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
- CheckExplicitlyDefaultedSpecialMember(M);
-
- // 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()) {
- if (CSM != CXXInvalid) {
- M->setTrivial(SpecialMemberIsTrivial(M, CSM));
- // Inform the class that we've finished declaring this member.
- Record->finishedDefaultedOrDeletedMember(M);
- M->setTrivialForCall(
- HasTrivialABI ||
- SpecialMemberIsTrivial(M, CSM, TAH_ConsiderTrivialABI));
- Record->setTrivialForCallFlags(M);
- }
- }
- // Set triviality for the purpose of calls if this is a user-provided
- // copy/move constructor or destructor.
- if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor ||
- CSM == CXXDestructor) && M->isUserProvided()) {
- M->setTrivialForCall(HasTrivialABI);
- Record->setTrivialForCallFlags(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);
- }
- }
+ if (!isa<CXXDestructorDecl>(M))
+ CompleteMemberFunction(M);
}
}
@@ -6553,7 +6613,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
ReturnType = Type->getReturnType();
QualType DeclType = Context.getTypeDeclType(RD);
- DeclType = Context.getAddrSpaceQualType(DeclType, MD->getTypeQualifiers().getAddressSpace());
+ DeclType = Context.getAddrSpaceQualType(DeclType, MD->getMethodQualifiers().getAddressSpace());
QualType ExpectedReturnType = Context.getLValueReferenceType(DeclType);
if (!Context.hasSameType(ReturnType, ExpectedReturnType)) {
@@ -6563,7 +6623,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
}
// A defaulted special member cannot have cv-qualifiers.
- if (Type->getTypeQuals().hasConst() || Type->getTypeQuals().hasVolatile()) {
+ if (Type->getMethodQuals().hasConst() || Type->getMethodQuals().hasVolatile()) {
if (DeleteOnTypeMismatch)
ShouldDeleteForTypeMismatch = true;
else {
@@ -6623,49 +6683,42 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// makes such functions always instantiate to constexpr functions. For
// functions which cannot be constexpr (for non-constructors in C++11 and for
// destructors in C++1y), this is checked elsewhere.
+ //
+ // FIXME: This should not apply if the member is deleted.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
: isa<CXXConstructorDecl>(MD)) &&
MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
- Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr) << CSM;
+ Diag(MD->getBeginLoc(), MD->isConsteval()
+ ? diag::err_incorrect_defaulted_consteval
+ : diag::err_incorrect_defaulted_constexpr)
+ << CSM;
// FIXME: Explain why the special member can't be constexpr.
HadError = true;
}
- // and may have an explicit exception-specification only if it is compatible
- // with the exception-specification on the implicit declaration.
- if (Type->hasExceptionSpec()) {
- // Delay the check if this is the first declaration of the special member,
- // since we may not have parsed some necessary in-class initializers yet.
- if (First) {
- // If the exception specification needs to be instantiated, do so now,
- // before we clobber it with an EST_Unevaluated specification below.
- if (Type->getExceptionSpecType() == EST_Uninstantiated) {
- InstantiateExceptionSpec(MD->getBeginLoc(), MD);
- Type = MD->getType()->getAs<FunctionProtoType>();
- }
- DelayedDefaultedMemberExceptionSpecs.push_back(std::make_pair(MD, Type));
- } else
- CheckExplicitlyDefaultedMemberExceptionSpec(MD, Type);
- }
-
- // If a function is explicitly defaulted on its first declaration,
if (First) {
- // -- it is implicitly considered to be constexpr if the implicit
- // definition would be,
- MD->setConstexpr(Constexpr);
-
- // -- it is implicitly considered to have the same exception-specification
- // as if it had been implicitly declared,
- FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
- EPI.ExceptionSpec.Type = EST_Unevaluated;
- EPI.ExceptionSpec.SourceDecl = MD;
- MD->setType(Context.getFunctionType(ReturnType,
- llvm::makeArrayRef(&ArgType,
- ExpectedParams),
- EPI));
+ // C++2a [dcl.fct.def.default]p3:
+ // If a function is explicitly defaulted on its first declaration, it is
+ // implicitly considered to be constexpr if the implicit declaration
+ // would be.
+ MD->setConstexprKind(Constexpr ? CSK_constexpr : CSK_unspecified);
+
+ if (!Type->hasExceptionSpec()) {
+ // C++2a [except.spec]p3:
+ // If a declaration of a function does not have a noexcept-specifier
+ // [and] is defaulted on its first declaration, [...] the exception
+ // specification is as specified below
+ FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = MD;
+ MD->setType(Context.getFunctionType(ReturnType,
+ llvm::makeArrayRef(&ArgType,
+ ExpectedParams),
+ EPI));
+ }
}
if (ShouldDeleteForTypeMismatch || ShouldDeleteSpecialMember(MD, CSM)) {
@@ -6698,43 +6751,12 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
MD->setInvalidDecl();
}
-/// Check whether the exception specification provided for an
-/// explicitly-defaulted special member matches the exception specification
-/// that would have been generated for an implicit special member, per
-/// C++11 [dcl.fct.def.default]p2.
-void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
- CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
- // If the exception specification was explicitly specified but hadn't been
- // parsed when the method was defaulted, grab it now.
- if (SpecifiedType->getExceptionSpecType() == EST_Unparsed)
- SpecifiedType =
- MD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
-
- // Compute the implicit exception specification.
- CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false,
- /*IsCXXMethod=*/true);
- FunctionProtoType::ExtProtoInfo EPI(CC);
- auto IES = computeImplicitExceptionSpec(*this, MD->getLocation(), MD);
- EPI.ExceptionSpec = IES.getExceptionSpec();
- const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
- Context.getFunctionType(Context.VoidTy, None, EPI));
-
- // Ensure that it matches.
- CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec)
- << getSpecialMember(MD), PDiag(),
- ImplicitType, SourceLocation(),
- SpecifiedType, MD->getLocation());
-}
-
void Sema::CheckDelayedMemberExceptionSpecs() {
decltype(DelayedOverridingExceptionSpecChecks) Overriding;
decltype(DelayedEquivalentExceptionSpecChecks) Equivalent;
- decltype(DelayedDefaultedMemberExceptionSpecs) Defaulted;
std::swap(Overriding, DelayedOverridingExceptionSpecChecks);
std::swap(Equivalent, DelayedEquivalentExceptionSpecChecks);
- std::swap(Defaulted, DelayedDefaultedMemberExceptionSpecs);
// Perform any deferred checking of exception specifications for virtual
// destructors.
@@ -6745,11 +6767,6 @@ void Sema::CheckDelayedMemberExceptionSpecs() {
// special members.
for (auto &Check : Equivalent)
CheckEquivalentExceptionSpec(Check.second, Check.first);
-
- // Check that any explicitly-defaulted methods have exception specifications
- // compatible with their implicit exception specifications.
- for (auto &Spec : Defaulted)
- CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second);
}
namespace {
@@ -6891,6 +6908,8 @@ struct SpecialMemberDeletionInfo
return ICI ? Sema::CXXInvalid : CSM;
}
+ bool shouldDeleteForVariantObjCPtrMember(FieldDecl *FD, QualType FieldType);
+
bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); }
bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); }
@@ -6962,13 +6981,14 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
S.Diag(Field->getLocation(),
diag::note_deleted_special_member_class_subobject)
<< getEffectiveCSM() << MD->getParent() << /*IsField*/true
- << Field << DiagKind << IsDtorCallInCtor;
+ << Field << DiagKind << IsDtorCallInCtor << /*IsObjCPtr*/false;
} else {
CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>();
S.Diag(Base->getBeginLoc(),
diag::note_deleted_special_member_class_subobject)
<< getEffectiveCSM() << MD->getParent() << /*IsField*/ false
- << Base->getType() << DiagKind << IsDtorCallInCtor;
+ << Base->getType() << DiagKind << IsDtorCallInCtor
+ << /*IsObjCPtr*/false;
}
if (DiagKind == 1)
@@ -7020,6 +7040,30 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
return false;
}
+bool SpecialMemberDeletionInfo::shouldDeleteForVariantObjCPtrMember(
+ FieldDecl *FD, QualType FieldType) {
+ // The defaulted special functions are defined as deleted if this is a variant
+ // member with a non-trivial ownership type, e.g., ObjC __strong or __weak
+ // type under ARC.
+ if (!FieldType.hasNonTrivialObjCLifetime())
+ return false;
+
+ // Don't make the defaulted default constructor defined as deleted if the
+ // member has an in-class initializer.
+ if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer())
+ return false;
+
+ if (Diagnose) {
+ auto *ParentClass = cast<CXXRecordDecl>(FD->getParent());
+ S.Diag(FD->getLocation(),
+ diag::note_deleted_special_member_class_subobject)
+ << getEffectiveCSM() << ParentClass << /*IsField*/true
+ << FD << 4 << /*IsDtorCallInCtor*/false << /*IsObjCPtr*/true;
+ }
+
+ return true;
+}
+
/// Check whether we should delete a special member function due to the class
/// having a particular direct or virtual base class.
bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
@@ -7040,7 +7084,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
S.Diag(Base->getBeginLoc(),
diag::note_deleted_special_member_class_subobject)
<< getEffectiveCSM() << MD->getParent() << /*IsField*/ false
- << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false;
+ << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false
+ << /*IsObjCPtr*/false;
S.NoteDeletedFunction(BaseCtor);
}
return BaseCtor->isDeleted();
@@ -7054,6 +7099,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
QualType FieldType = S.Context.getBaseElementType(FD->getType());
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+ if (inUnion() && shouldDeleteForVariantObjCPtrMember(FD, FieldType))
+ return true;
+
if (CSM == Sema::CXXDefaultConstructor) {
// For a default constructor, all references must be initialized in-class
// and, if a union, it must have a non-const member.
@@ -7115,6 +7163,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
for (auto *UI : FieldRecord->fields()) {
QualType UnionFieldType = S.Context.getBaseElementType(UI->getType());
+ if (shouldDeleteForVariantObjCPtrMember(&*UI, UnionFieldType))
+ return true;
+
if (!UnionFieldType.isConstQualified())
AllVariantFieldsAreConst = false;
@@ -7187,7 +7238,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
// The closure type associated with a lambda-expression has a
// deleted (8.4.3) default constructor and a deleted copy
// assignment operator.
- // C++2a adds back these operators if the lambda has no capture-default.
+ // C++2a adds back these operators if the lambda has no lambda-capture.
if (RD->isLambda() && !RD->lambdaIsDefaultConstructibleAndAssignable() &&
(CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) {
if (Diagnose)
@@ -7934,14 +7985,14 @@ void Sema::ActOnFinishCXXMemberSpecification(
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
if (ClassDecl->needsImplicitDefaultConstructor()) {
- ++ASTContext::NumImplicitDefaultConstructors;
+ ++getASTContext().NumImplicitDefaultConstructors;
if (ClassDecl->hasInheritedConstructor())
DeclareImplicitDefaultConstructor(ClassDecl);
}
if (ClassDecl->needsImplicitCopyConstructor()) {
- ++ASTContext::NumImplicitCopyConstructors;
+ ++getASTContext().NumImplicitCopyConstructors;
// If the properties or semantics of the copy constructor couldn't be
// determined while the class was being declared, force a declaration
@@ -7963,7 +8014,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
- ++ASTContext::NumImplicitMoveConstructors;
+ ++getASTContext().NumImplicitMoveConstructors;
if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
ClassDecl->hasInheritedConstructor())
@@ -7971,7 +8022,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
if (ClassDecl->needsImplicitCopyAssignment()) {
- ++ASTContext::NumImplicitCopyAssignmentOperators;
+ ++getASTContext().NumImplicitCopyAssignmentOperators;
// If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
@@ -7984,7 +8035,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
- ++ASTContext::NumImplicitMoveAssignmentOperators;
+ ++getASTContext().NumImplicitMoveAssignmentOperators;
// Likewise for the move assignment operator.
if (ClassDecl->isDynamicClass() ||
@@ -7994,7 +8045,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
if (ClassDecl->needsImplicitDestructor()) {
- ++ASTContext::NumImplicitDestructors;
+ ++getASTContext().NumImplicitDestructors;
// If we have a dynamic class, then the destructor may be virtual, so we
// have to declare the destructor immediately. This ensures that, e.g., it
@@ -8139,6 +8190,27 @@ void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *MethodD) {
CheckCXXDefaultArguments(Method);
}
+// Emit the given diagnostic for each non-address-space qualifier.
+// Common part of CheckConstructorDeclarator and CheckDestructorDeclarator.
+static void checkMethodTypeQualifiers(Sema &S, Declarator &D, unsigned DiagID) {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+ if (FTI.hasMethodTypeQualifiers() && !D.isInvalidType()) {
+ bool DiagOccured = false;
+ FTI.MethodQualifiers->forEachQualifier(
+ [DiagID, &S, &DiagOccured](DeclSpec::TQ, StringRef QualName,
+ SourceLocation SL) {
+ // This diagnostic should be emitted on any qualifier except an addr
+ // space qualifier. However, forEachQualifier currently doesn't visit
+ // addr space qualifiers, so there's no way to write this condition
+ // right now; we just diagnose on everything.
+ S.Diag(SL, DiagID) << QualName << SourceRange(SL);
+ DiagOccured = true;
+ });
+ if (DiagOccured)
+ D.setInvalidType();
+ }
+}
+
/// CheckConstructorDeclarator - Called by ActOnDeclarator to check
/// the well-formedness of the constructor declarator @p D with type @p
/// R. If there are any errors in the declarator, this routine will
@@ -8179,18 +8251,11 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
D.setInvalidType();
}
- DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
- if (FTI.hasMethodTypeQualifiers()) {
- FTI.MethodQualifiers->forEachQualifier(
- [&](DeclSpec::TQ TypeQual, StringRef QualName, SourceLocation SL) {
- Diag(SL, diag::err_invalid_qualified_constructor)
- << QualName << SourceRange(SL);
- });
- D.setInvalidType();
- }
+ checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_constructor);
// C++0x [class.ctor]p4:
// A constructor shall not be declared with a ref-qualifier.
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
if (FTI.hasRefQualifier()) {
Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor)
<< FTI.RefQualifierIsLValueRef
@@ -8365,18 +8430,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
}
}
- DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
- if (FTI.hasMethodTypeQualifiers() && !D.isInvalidType()) {
- FTI.MethodQualifiers->forEachQualifier(
- [&](DeclSpec::TQ TypeQual, StringRef QualName, SourceLocation SL) {
- Diag(SL, diag::err_invalid_qualified_destructor)
- << QualName << SourceRange(SL);
- });
- D.setInvalidType();
- }
+ checkMethodTypeQualifiers(*this, D, diag::err_invalid_qualified_destructor);
// C++0x [class.dtor]p2:
// A destructor shall not be declared with a ref-qualifier.
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
if (FTI.hasRefQualifier()) {
Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_destructor)
<< FTI.RefQualifierIsLValueRef
@@ -8590,12 +8648,12 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
- if (DS.isExplicitSpecified())
+ if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a)
Diag(DS.getExplicitSpecLoc(),
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_explicit_conversion_functions
: diag::ext_explicit_conversion_functions)
- << SourceRange(DS.getExplicitSpecLoc());
+ << SourceRange(DS.getExplicitSpecRange());
}
/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
@@ -8699,7 +8757,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
// We leave 'friend' and 'virtual' to be rejected in the normal way.
if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() ||
DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() ||
- DS.isNoreturnSpecified() || DS.isConstexprSpecified()) {
+ DS.isNoreturnSpecified() || DS.hasConstexprSpecifier()) {
BadSpecifierDiagnoser Diagnoser(
*this, D.getIdentifierLoc(),
diag::err_deduction_guide_invalid_specifier);
@@ -8997,6 +9055,9 @@ void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) {
PopDeclContext();
if (Namespc->hasAttr<VisibilityAttr>())
PopPragmaVisibility(true, RBrace);
+ // If this namespace contains an export-declaration, export it now.
+ if (DeferredExportedNamespaces.erase(Namespc))
+ Dcl->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported);
}
CXXRecordDecl *Sema::getStdBadAlloc() const {
@@ -9316,13 +9377,17 @@ static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) {
namespace {
// Callback to only accept typo corrections that are namespaces.
-class NamespaceValidatorCCC : public CorrectionCandidateCallback {
+class NamespaceValidatorCCC final : public CorrectionCandidateCallback {
public:
bool ValidateCandidate(const TypoCorrection &candidate) override {
if (NamedDecl *ND = candidate.getCorrectionDecl())
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
return false;
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<NamespaceValidatorCCC>(*this);
+ }
};
}
@@ -9332,9 +9397,9 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
R.clear();
+ NamespaceValidatorCCC CCC{};
if (TypoCorrection Corrected =
- S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS,
- llvm::make_unique<NamespaceValidatorCCC>(),
+ S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS, CCC,
Sema::CTK_ErrorRecovery)) {
if (DeclContext *DC = S.computeDeclContext(SS, false)) {
std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
@@ -9737,7 +9802,7 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
NonTemplateTarget = TargetTD->getTemplatedDecl();
UsingShadowDecl *Shadow;
- if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+ if (NonTemplateTarget && isa<CXXConstructorDecl>(NonTemplateTarget)) {
bool IsVirtualBase =
isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
UD->getQualifier()->getAsRecordDecl());
@@ -9829,7 +9894,7 @@ static CXXBaseSpecifier *findDirectBaseWithType(CXXRecordDecl *Derived,
}
namespace {
-class UsingValidatorCCC : public CorrectionCandidateCallback {
+class UsingValidatorCCC final : public CorrectionCandidateCallback {
public:
UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation,
NestedNameSpecifier *NNS, CXXRecordDecl *RequireMemberOf)
@@ -9899,6 +9964,10 @@ public:
return !HasTypenameKeyword;
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<UsingValidatorCCC>(*this);
+ }
+
private:
bool HasTypenameKeyword;
bool IsInstantiation;
@@ -10055,12 +10124,11 @@ NamedDecl *Sema::BuildUsingDeclaration(
isa<TranslationUnitDecl>(LookupContext) &&
getSourceManager().isInSystemHeader(UsingLoc))
return nullptr;
- if (TypoCorrection Corrected = CorrectTypo(
- R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- llvm::make_unique<UsingValidatorCCC>(
- HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
- dyn_cast<CXXRecordDecl>(CurContext)),
- CTK_ErrorRecovery)) {
+ UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
+ dyn_cast<CXXRecordDecl>(CurContext));
+ if (TypoCorrection Corrected =
+ CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC,
+ CTK_ErrorRecovery)) {
// We reject candidates where DroppedSpecifier == true, hence the
// literal '0' below.
diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
@@ -10808,6 +10876,28 @@ struct ComputingExceptionSpec {
};
}
+bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
+ llvm::APSInt Result;
+ ExprResult Converted = CheckConvertedConstantExpression(
+ ExplicitSpec.getExpr(), Context.BoolTy, Result, CCEK_ExplicitBool);
+ ExplicitSpec.setExpr(Converted.get());
+ if (Converted.isUsable() && !Converted.get()->isValueDependent()) {
+ ExplicitSpec.setKind(Result.getBoolValue()
+ ? ExplicitSpecKind::ResolvedTrue
+ : ExplicitSpecKind::ResolvedFalse);
+ return true;
+ }
+ ExplicitSpec.setKind(ExplicitSpecKind::Unresolved);
+ return false;
+}
+
+ExplicitSpecifier Sema::ActOnExplicitBoolSpecifier(Expr *ExplicitExpr) {
+ ExplicitSpecifier ES(ExplicitExpr, ExplicitSpecKind::Unresolved);
+ if (!ExplicitExpr->isTypeDependent())
+ tryResolveExplicitSpecifier(ES);
+ return ES;
+}
+
static Sema::ImplicitExceptionSpecification
ComputeDefaultedSpecialMemberExceptionSpec(
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
@@ -10956,9 +11046,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
= Context.DeclarationNames.getCXXConstructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(),
- /*TInfo=*/nullptr, /*isExplicit=*/false, /*isInline=*/true,
- /*isImplicitlyDeclared=*/true, Constexpr);
+ Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(),
+ /*TInfo=*/nullptr, ExplicitSpecifier(),
+ /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
@@ -10976,7 +11067,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
// Note that we have declared this constructor.
- ++ASTContext::NumImplicitDefaultConstructorsDeclared;
+ ++getASTContext().NumImplicitDefaultConstructorsDeclared;
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, DefaultCon);
@@ -11077,8 +11168,9 @@ Sema::findInheritingConstructor(SourceLocation Loc,
CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
- BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true, Constexpr,
+ BaseCtor->getExplicitSpecifier(), /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified,
InheritedConstructor(Shadow, BaseCtor));
if (Shadow->isInvalidDecl())
DerivedCtor->setInvalidDecl();
@@ -11098,7 +11190,7 @@ Sema::findInheritingConstructor(SourceLocation Loc,
Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
ParmVarDecl *PD = ParmVarDecl::Create(
Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
- FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
+ FPT->getParamType(I), TInfo, SC_None, /*DefArg=*/nullptr);
PD->setScopeInfo(0, I);
PD->setImplicit();
// Ensure attributes are propagated onto parameters (this matters for
@@ -11249,7 +11341,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
ClassDecl->hasTrivialDestructorForCall());
// Note that we have declared this destructor.
- ++ASTContext::NumImplicitDestructorsDeclared;
+ ++getASTContext().NumImplicitDestructorsDeclared;
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, Destructor);
@@ -11319,7 +11411,6 @@ void Sema::ActOnFinishCXXMemberDecls() {
if (Record->isInvalidDecl()) {
DelayedOverridingExceptionSpecChecks.clear();
DelayedEquivalentExceptionSpecChecks.clear();
- DelayedDefaultedMemberExceptionSpecs.clear();
return;
}
checkForMultipleExportedDefaultConstructors(*this, Record);
@@ -11399,7 +11490,7 @@ class RefBuilder: public ExprBuilder {
public:
Expr *build(Sema &S, SourceLocation Loc) const override {
- return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc).get());
+ return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc));
}
RefBuilder(VarDecl *Var, QualType VarType)
@@ -11551,7 +11642,7 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
Expr *CallArgs[] = {
To, From, IntegerLiteral::Create(S.Context, Size, SizeType, Loc)
};
- ExprResult Call = S.ActOnCallExpr(/*Scope=*/nullptr, MemCpyRef.get(),
+ ExprResult Call = S.BuildCallExpr(/*Scope=*/nullptr, MemCpyRef.get(),
Loc, CallArgs, Loc);
assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
@@ -11660,7 +11751,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Create the reference to operator=.
ExprResult OpEqualRef
- = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*isArrow=*/false,
+ = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*IsArrow=*/false,
SS, /*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/nullptr,
OpLookup,
@@ -11810,14 +11901,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ if (Context.getLangOpts().OpenCLCPlusPlus)
+ ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
QualType RetType = Context.getLValueReferenceType(ArgType);
bool Const = ClassDecl->implicitCopyAssignmentHasConstParam();
if (Const)
ArgType = ArgType.withConst();
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
-
ArgType = Context.getLValueReferenceType(ArgType);
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
@@ -11829,10 +11919,11 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXMethodDecl *CopyAssignment =
- CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
- /*isInline=*/true, Constexpr, SourceLocation());
+ CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+ /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+ /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified,
+ SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
@@ -11860,7 +11951,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
: ClassDecl->hasTrivialCopyAssignment());
// Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+ ++getASTContext().NumImplicitCopyAssignmentOperatorsDeclared;
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, CopyAssignment);
@@ -12009,7 +12100,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
DerefBuilder DerefThis(This);
CastBuilder To(DerefThis,
Context.getQualifiedType(
- BaseType, CopyAssignOperator->getTypeQualifiers()),
+ BaseType, CopyAssignOperator->getMethodQualifiers()),
VK_LValue, BasePath);
// Build the copy.
@@ -12135,6 +12226,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules.
QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ if (Context.getLangOpts().OpenCLCPlusPlus)
+ ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
QualType RetType = Context.getLValueReferenceType(ArgType);
ArgType = Context.getRValueReferenceType(ArgType);
@@ -12147,10 +12240,11 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXMethodDecl *MoveAssignment =
- CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
- /*isInline=*/true, Constexpr, SourceLocation());
+ CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create(
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+ /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+ /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified,
+ SourceLocation());
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
@@ -12181,7 +12275,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
: ClassDecl->hasTrivialMoveAssignment());
// Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+ ++getASTContext().NumImplicitMoveAssignmentOperatorsDeclared;
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, MoveAssignment);
@@ -12374,7 +12468,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Implicitly cast "this" to the appropriately-qualified base type.
CastBuilder To(DerefThis,
Context.getQualifiedType(
- BaseType, MoveAssignOperator->getTypeQualifiers()),
+ BaseType, MoveAssignOperator->getMethodQualifiers()),
VK_LValue, BasePath);
// Build the move.
@@ -12529,8 +12623,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// member of its class.
CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
- /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
- Constexpr);
+ ExplicitSpecifier(),
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
@@ -12564,7 +12660,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
: ClassDecl->hasTrivialCopyConstructorForCall()));
// Note that we have declared this constructor.
- ++ASTContext::NumImplicitCopyConstructorsDeclared;
+ ++getASTContext().NumImplicitCopyConstructorsDeclared;
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
@@ -12659,8 +12755,10 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// member of its class.
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
- /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
- Constexpr);
+ ExplicitSpecifier(),
+ /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
@@ -12694,7 +12792,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
: ClassDecl->hasTrivialMoveConstructorForCall()));
// Note that we have declared this constructor.
- ++ASTContext::NumImplicitMoveConstructorsDeclared;
+ ++getASTContext().NumImplicitMoveConstructorsDeclared;
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, MoveConstructor);
@@ -12798,7 +12896,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// Construct the body of the conversion function { return __invoke; }.
Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
- VK_LValue, Conv->getLocation()).get();
+ VK_LValue, Conv->getLocation());
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(),
@@ -12981,7 +13079,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
// If we already have the in-class initializer nothing needs to be done.
if (Field->getInClassInitializer())
- return CXXDefaultInitExpr::Create(Context, Loc, Field);
+ return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext);
// If we might have already tried and failed to instantiate, don't try again.
if (Field->isInvalidDecl())
@@ -13022,7 +13120,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
Field->setInvalidDecl();
return ExprError();
}
- return CXXDefaultInitExpr::Create(Context, Loc, Field);
+ return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext);
}
// DR1351:
@@ -13061,12 +13159,17 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
return;
CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
- MarkFunctionReferenced(VD->getLocation(), Destructor);
- CheckDestructorAccess(VD->getLocation(), Destructor,
- PDiag(diag::err_access_dtor_var)
- << VD->getDeclName()
- << VD->getType());
- DiagnoseUseOfDecl(Destructor, VD->getLocation());
+
+ // If this is an array, we'll require the destructor during initialization, so
+ // we can skip over this. We still want to emit exit-time destructor warnings
+ // though.
+ if (!VD->getType()->isArrayType()) {
+ MarkFunctionReferenced(VD->getLocation(), Destructor);
+ CheckDestructorAccess(VD->getLocation(), Destructor,
+ PDiag(diag::err_access_dtor_var)
+ << VD->getDeclName() << VD->getType());
+ DiagnoseUseOfDecl(Destructor, VD->getLocation());
+ }
if (Destructor->isTrivial()) return;
if (!VD->hasGlobalStorage()) return;
@@ -13169,7 +13272,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
diag::err_operator_new_delete_dependent_result_type)
<< FnDecl->getDeclName() << ExpectedResultType;
- // OpenCL C++: the operator is valid on any address space.
+ // The operator is valid on any address space for OpenCL.
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
if (auto *PtrTy = ResultType->getAs<PointerType>()) {
ResultType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
@@ -13202,7 +13305,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
// Check that the first parameter type is what we expect.
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
- // OpenCL C++: the operator is valid on any address space.
+ // The operator is valid on any address space for OpenCL.
if (auto *PtrTy =
FnDecl->getParamDecl(0)->getType()->getAs<PointerType>()) {
FirstParamType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
@@ -13910,8 +14013,6 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr);
if (Converted.isInvalid())
Failed = true;
- else
- Converted = ConstantExpr::Create(Context, Converted.get());
llvm::APSInt Cond;
if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond,
@@ -15155,7 +15256,8 @@ void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
}
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
- const CXXRecordDecl *RD) {
+ const CXXRecordDecl *RD,
+ bool ConstexprOnly) {
// Mark all functions which will appear in RD's vtable as used.
CXXFinalOverriderMap FinalOverriders;
RD->getFinalOverriders(FinalOverriders);
@@ -15170,7 +15272,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
- if (!Overrider->isPure())
+ if (!Overrider->isPure() && (!ConstexprOnly || Overrider->isConstexpr()))
MarkFunctionReferenced(Loc, Overrider);
}
}
@@ -15387,6 +15489,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
case EST_Uninstantiated:
case EST_Unevaluated:
case EST_BasicNoexcept:
+ case EST_NoThrow:
case EST_DynamicNone:
case EST_MSAny:
case EST_None:
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 3746bdad0358..e629837eb71d 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1,9 +1,8 @@
//===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -360,6 +359,7 @@ HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) {
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
+ ImplicitlyRetainedSelfLocs.clear();
assert((getCurMethodDecl() == nullptr) && "Methodparsing confused");
ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D);
@@ -500,7 +500,7 @@ namespace {
// Callback to only accept typo corrections that are Objective-C classes.
// If an ObjCInterfaceDecl* is given to the constructor, then the validation
// function will reject corrections to that class.
-class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {
+class ObjCInterfaceValidatorCCC final : public CorrectionCandidateCallback {
public:
ObjCInterfaceValidatorCCC() : CurrentIDecl(nullptr) {}
explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl)
@@ -511,6 +511,10 @@ class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {
return ID && !declaresSameEntity(ID, CurrentIDecl);
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<ObjCInterfaceValidatorCCC>(*this);
+ }
+
private:
ObjCInterfaceDecl *CurrentIDecl;
};
@@ -550,11 +554,10 @@ ActOnSuperClassOfClassInterface(Scope *S,
if (!PrevDecl) {
// Try to correct for a typo in the superclass name without correcting
// to the class we're defining.
+ ObjCInterfaceValidatorCCC CCC(IDecl);
if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(SuperName, SuperLoc),
- LookupOrdinaryName, TUScope,
- nullptr, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl),
- CTK_ErrorRecovery)) {
+ DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName,
+ TUScope, nullptr, CCC, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
@@ -1293,11 +1296,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer,
for (const IdentifierLocPair &Pair : ProtocolId) {
ObjCProtocolDecl *PDecl = LookupProtocol(Pair.first, Pair.second);
if (!PDecl) {
+ DeclFilterCCC<ObjCProtocolDecl> CCC{};
TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(Pair.first, Pair.second),
- LookupObjCProtocolName, TUScope, nullptr,
- llvm::make_unique<DeclFilterCCC<ObjCProtocolDecl>>(),
- CTK_ErrorRecovery);
+ DeclarationNameInfo(Pair.first, Pair.second), LookupObjCProtocolName,
+ TUScope, nullptr, CCC, CTK_ErrorRecovery);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
<< Pair.first);
@@ -1335,7 +1337,8 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer,
namespace {
// Callback to only accept typo corrections that are either
// Objective-C protocols or valid Objective-C type arguments.
-class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback {
+class ObjCTypeArgOrProtocolValidatorCCC final
+ : public CorrectionCandidateCallback {
ASTContext &Context;
Sema::LookupNameKind LookupKind;
public:
@@ -1382,6 +1385,10 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback {
return false;
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this);
+ }
};
} // end anonymous namespace
@@ -1580,7 +1587,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
// add the '*'.
if (type->getAs<ObjCInterfaceType>()) {
SourceLocation starLoc = getLocForEndOfToken(loc);
- D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc,
+ D.AddTypeInfo(DeclaratorChunk::getPointer(/*TypeQuals=*/0, starLoc,
SourceLocation(),
SourceLocation(),
SourceLocation(),
@@ -1671,12 +1678,10 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
}
// Perform typo correction on the name.
- TypoCorrection corrected = CorrectTypo(
- DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S,
- nullptr,
- llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context,
- lookupKind),
- CTK_ErrorRecovery);
+ ObjCTypeArgOrProtocolValidatorCCC CCC(Context, lookupKind);
+ TypoCorrection corrected =
+ CorrectTypo(DeclarationNameInfo(identifiers[i], identifierLocs[i]),
+ lookupKind, S, nullptr, CCC, CTK_ErrorRecovery);
if (corrected) {
// Did we find a protocol?
if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) {
@@ -1888,7 +1893,8 @@ Decl *Sema::ActOnStartCategoryInterface(
Decl *Sema::ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *CatName, SourceLocation CatLoc) {
+ IdentifierInfo *CatName, SourceLocation CatLoc,
+ const ParsedAttributesView &Attrs) {
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
ObjCCategoryDecl *CatIDecl = nullptr;
if (IDecl && IDecl->hasDefinition()) {
@@ -1916,6 +1922,9 @@ Decl *Sema::ActOnStartCategoryImplementation(
CDecl->setInvalidDecl();
}
+ ProcessDeclAttributeList(TUScope, CDecl, Attrs);
+ AddPragmaAttributes(TUScope, CDecl);
+
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
@@ -1951,7 +1960,8 @@ Decl *Sema::ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *SuperClassname,
- SourceLocation SuperClassLoc) {
+ SourceLocation SuperClassLoc,
+ const ParsedAttributesView &Attrs) {
ObjCInterfaceDecl *IDecl = nullptr;
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
@@ -1968,9 +1978,10 @@ Decl *Sema::ActOnStartClassImplementation(
} else {
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
- TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
- nullptr, llvm::make_unique<ObjCInterfaceValidatorCCC>(), CTK_NonError);
+ ObjCInterfaceValidatorCCC CCC{};
+ TypoCorrection Corrected =
+ CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
+ LookupOrdinaryName, TUScope, nullptr, CCC, CTK_NonError);
if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// Suggest the (potentially) correct interface name. Don't provide a
// code-modification hint or use the typo name for recovery, because
@@ -2044,6 +2055,9 @@ Decl *Sema::ActOnStartClassImplementation(
ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl,
ClassLoc, AtClassImplLoc, SuperClassLoc);
+ ProcessDeclAttributeList(TUScope, IMPDecl, Attrs);
+ AddPragmaAttributes(TUScope, IMPDecl);
+
if (CheckObjCDeclScope(IMPDecl))
return ActOnObjCContainerStartDefinition(IMPDecl);
@@ -4047,6 +4061,9 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
}
}
+ if (IDecl->hasAttr<ObjCClassStubAttr>())
+ Diag(IC->getLocation(), diag::err_implementation_of_class_stub);
+
if (LangOpts.ObjCRuntime.isNonFragile()) {
while (IDecl->getSuperClass()) {
DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass());
@@ -4075,6 +4092,10 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
Diag(Super->getLocation(), diag::note_class_declared);
}
}
+
+ if (IntfDecl->hasAttr<ObjCClassStubAttr>() &&
+ !IntfDecl->hasAttr<ObjCSubclassingRestrictedAttr>())
+ Diag(IntfDecl->getLocation(), diag::err_class_stub_subclassing_mismatch);
}
DiagnoseVariableSizedIvars(*this, OCD);
if (isInterfaceDeclKind) {
@@ -4152,13 +4173,12 @@ namespace {
/// overrides.
class OverrideSearch {
public:
- Sema &S;
- ObjCMethodDecl *Method;
+ const ObjCMethodDecl *Method;
llvm::SmallSetVector<ObjCMethodDecl*, 4> Overridden;
bool Recursive;
public:
- OverrideSearch(Sema &S, ObjCMethodDecl *method) : S(S), Method(method) {
+ OverrideSearch(Sema &S, const ObjCMethodDecl *method) : Method(method) {
Selector selector = method->getSelector();
// Bypass this search if we've never seen an instance/class method
@@ -4172,19 +4192,20 @@ public:
if (it == S.MethodPool.end())
return;
}
- ObjCMethodList &list =
+ const ObjCMethodList &list =
method->isInstanceMethod() ? it->second.first : it->second.second;
if (!list.getMethod()) return;
- ObjCContainerDecl *container
+ const ObjCContainerDecl *container
= cast<ObjCContainerDecl>(method->getDeclContext());
// Prevent the search from reaching this container again. This is
// important with categories, which override methods from the
// interface and each other.
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(container)) {
+ if (const ObjCCategoryDecl *Category =
+ dyn_cast<ObjCCategoryDecl>(container)) {
searchFromContainer(container);
- if (ObjCInterfaceDecl *Interface = Category->getClassInterface())
+ if (const ObjCInterfaceDecl *Interface = Category->getClassInterface())
searchFromContainer(Interface);
} else {
searchFromContainer(container);
@@ -4196,7 +4217,7 @@ public:
iterator end() const { return Overridden.end(); }
private:
- void searchFromContainer(ObjCContainerDecl *container) {
+ void searchFromContainer(const ObjCContainerDecl *container) {
if (container->isInvalidDecl()) return;
switch (container->getDeclKind()) {
@@ -4212,7 +4233,7 @@ private:
}
}
- void searchFrom(ObjCProtocolDecl *protocol) {
+ void searchFrom(const ObjCProtocolDecl *protocol) {
if (!protocol->hasDefinition())
return;
@@ -4221,14 +4242,14 @@ private:
search(protocol->getReferencedProtocols());
}
- void searchFrom(ObjCCategoryDecl *category) {
+ void searchFrom(const ObjCCategoryDecl *category) {
// A method in a category declaration overrides declarations from
// the main class and from protocols the category references.
// The main class is handled in the constructor.
search(category->getReferencedProtocols());
}
- void searchFrom(ObjCCategoryImplDecl *impl) {
+ void searchFrom(const ObjCCategoryImplDecl *impl) {
// A method in a category definition that has a category
// declaration overrides declarations from the category
// declaration.
@@ -4238,12 +4259,12 @@ private:
search(Interface);
// Otherwise it overrides declarations from the class.
- } else if (ObjCInterfaceDecl *Interface = impl->getClassInterface()) {
+ } else if (const auto *Interface = impl->getClassInterface()) {
search(Interface);
}
}
- void searchFrom(ObjCInterfaceDecl *iface) {
+ void searchFrom(const ObjCInterfaceDecl *iface) {
// A method in a class declaration overrides declarations from
if (!iface->hasDefinition())
return;
@@ -4260,20 +4281,19 @@ private:
search(iface->getReferencedProtocols());
}
- void searchFrom(ObjCImplementationDecl *impl) {
+ void searchFrom(const ObjCImplementationDecl *impl) {
// A method in a class implementation overrides declarations from
// the class interface.
- if (ObjCInterfaceDecl *Interface = impl->getClassInterface())
+ if (const auto *Interface = impl->getClassInterface())
search(Interface);
}
void search(const ObjCProtocolList &protocols) {
- for (ObjCProtocolList::iterator i = protocols.begin(), e = protocols.end();
- i != e; ++i)
- search(*i);
+ for (const auto *Proto : protocols)
+ search(Proto);
}
- void search(ObjCContainerDecl *container) {
+ void search(const ObjCContainerDecl *container) {
// Check for a method in this container which matches this selector.
ObjCMethodDecl *meth = container->getMethod(Method->getSelector(),
Method->isInstanceMethod(),
@@ -4299,6 +4319,8 @@ private:
void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
ObjCInterfaceDecl *CurrentClass,
ResultTypeCompatibilityKind RTC) {
+ if (!ObjCMethod)
+ return;
// Search for overridden methods and merge information down from them.
OverrideSearch overrides(*this, ObjCMethod);
// Keep track if the method overrides any method in the class's base classes,
@@ -4307,10 +4329,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
// For this info, a method in an implementation is not considered as
// overriding the same method in the interface or its categories.
bool hasOverriddenMethodsInBaseOrProtocol = false;
- for (OverrideSearch::iterator
- i = overrides.begin(), e = overrides.end(); i != e; ++i) {
- ObjCMethodDecl *overridden = *i;
-
+ for (ObjCMethodDecl *overridden : overrides) {
if (!hasOverriddenMethodsInBaseOrProtocol) {
if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
CurrentClass != overridden->getClassInterface() ||
@@ -4337,9 +4356,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
if (CategCount > 1 ||
!isa<ObjCCategoryImplDecl>(overridden->getDeclContext())) {
OverrideSearch overrides(*this, overridden);
- for (OverrideSearch::iterator
- OI= overrides.begin(), OE= overrides.end(); OI!=OE; ++OI) {
- ObjCMethodDecl *SuperOverridden = *OI;
+ for (ObjCMethodDecl *SuperOverridden : overrides) {
if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
CurrentClass != SuperOverridden->getClassInterface()) {
hasOverriddenMethodsInBaseOrProtocol = true;
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index e0850feaffc6..9fd924a8cad0 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -1,9 +1,8 @@
//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -382,6 +381,11 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// when declaring a replaceable global allocation function.
DiagID = diag::ext_missing_exception_specification;
ReturnValueOnError = false;
+ } else if (ESI.Type == EST_NoThrow) {
+ // Allow missing attribute 'nothrow' in redeclarations, since this is a very
+ // common omission.
+ DiagID = diag::ext_missing_exception_specification;
+ ReturnValueOnError = false;
} else {
DiagID = diag::err_missing_exception_specification;
ReturnValueOnError = true;
@@ -422,8 +426,14 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());
OS << ")";
break;
-
- default:
+ case EST_NoThrow:
+ OS <<"__attribute__((nothrow))";
+ break;
+ case EST_None:
+ case EST_MSAny:
+ case EST_Unevaluated:
+ case EST_Uninstantiated:
+ case EST_Unparsed:
llvm_unreachable("This spec type is compatible with none.");
}
@@ -734,6 +744,7 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID,
+ const PartialDiagnostic &NoThrowDiagID,
const FunctionProtoType *Superset,
SourceLocation SuperLoc,
const FunctionProtoType *Subset,
@@ -780,6 +791,16 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
Subset, SubLoc);
+ // Allow __declspec(nothrow) to be missing on redeclaration as an extension in
+ // some cases.
+ if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can &&
+ SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) {
+ Diag(SubLoc, NoThrowDiagID);
+ if (NoteID.getDiagID() != 0)
+ Diag(SuperLoc, NoteID);
+ return true;
+ }
+
// If the subset contains everything or the superset contains nothing, we've
// failed.
if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) ||
@@ -909,9 +930,9 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
// void (*q)(void (*) throw(int)) = p;
// }
// ... because it might be instantiated with T=int.
- return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(),
- ToFunc, From->getSourceRange().getBegin(),
- FromFunc, SourceLocation()) &&
+ return CheckExceptionSpecSubset(
+ PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc,
+ From->getSourceRange().getBegin(), FromFunc, SourceLocation()) &&
!getLangOpts().CPlusPlus17;
}
@@ -943,6 +964,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::err_deep_exception_specs_differ),
PDiag(diag::note_overridden_virtual_function),
+ PDiag(diag::ext_override_exception_spec),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(),
@@ -1179,6 +1201,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
@@ -1290,6 +1313,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::PredefinedExprClass:
case Expr::SizeOfPackExprClass:
case Expr::StringLiteralClass:
+ case Expr::SourceLocExprClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d5416d4d057c..d8869ffe945a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1,9 +1,8 @@
//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -311,6 +310,19 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return true;
}
+ // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions
+ // List-items in map clauses on this construct may only refer to the declared
+ // variable var and entities that could be referenced by a procedure defined
+ // at the same location
+ auto *DMD = dyn_cast<OMPDeclareMapperDecl>(CurContext);
+ if (LangOpts.OpenMP && DMD && !CurContext->containsDecl(D) &&
+ isa<VarDecl>(D)) {
+ Diag(Loc, diag::err_omp_declare_mapper_wrong_var)
+ << DMD->getVarName().getAsString();
+ Diag(D->getLocation(), diag::note_entity_declared_at) << D;
+ return true;
+ }
+
DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess,
AvoidPartialAvailabilityChecks, ClassReceiver);
@@ -321,17 +333,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return false;
}
-/// Retrieve the message suffix that should be added to a
-/// diagnostic complaining about the given function being deleted or
-/// unavailable.
-std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
- std::string Message;
- if (FD->getAvailability(&Message))
- return ": " + Message;
-
- return std::string();
-}
-
/// DiagnoseSentinelCalls - This routine checks whether a call or
/// message-send is to a declaration with the sentinel attribute, and
/// if so, it checks that the requirements of the sentinel are
@@ -624,15 +625,20 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
Context.getTargetInfo().getCXXABI().isMicrosoft())
(void)isCompleteType(E->getExprLoc(), T);
- UpdateMarkingForLValueToRValue(E);
+ ExprResult Res = CheckLValueToRValueConversionOperand(E);
+ if (Res.isInvalid())
+ return Res;
+ E = Res.get();
// Loading a __weak object implicitly retains the value, so we need a cleanup to
// balance that.
if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
Cleanup.setExprNeedsCleanups(true);
- ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
- nullptr, VK_RValue);
+ // C++ [conv.lval]p3:
+ // If T is cv std::nullptr_t, the result is a null pointer constant.
+ CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue;
+ Res = ImplicitCastExpr::Create(Context, T, CK, E, nullptr, VK_RValue);
// C11 6.3.2.1p2:
// ... if the lvalue has atomic type, the value has the non-atomic version
@@ -738,33 +744,20 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
return ExprError();
E = Res.get();
- QualType ScalarTy = Ty;
- unsigned NumElts = 0;
- if (const ExtVectorType *VecTy = Ty->getAs<ExtVectorType>()) {
- NumElts = VecTy->getNumElements();
- ScalarTy = VecTy->getElementType();
- }
-
// If this is a 'float' or '__fp16' (CVR qualified or typedef)
// promote to double.
// Note that default argument promotion applies only to float (and
// half/fp16); it does not apply to _Float16.
- const BuiltinType *BTy = ScalarTy->getAs<BuiltinType>();
+ const BuiltinType *BTy = Ty->getAs<BuiltinType>();
if (BTy && (BTy->getKind() == BuiltinType::Half ||
BTy->getKind() == BuiltinType::Float)) {
if (getLangOpts().OpenCL &&
!getOpenCLOptions().isEnabled("cl_khr_fp64")) {
- if (BTy->getKind() == BuiltinType::Half) {
- QualType Ty = Context.FloatTy;
- if (NumElts != 0)
- Ty = Context.getExtVectorType(Ty, NumElts);
- E = ImpCastExprToType(E, Ty, CK_FloatingCast).get();
- }
+ if (BTy->getKind() == BuiltinType::Half) {
+ E = ImpCastExprToType(E, Context.FloatTy, CK_FloatingCast).get();
+ }
} else {
- QualType Ty = Context.DoubleTy;
- if (NumElts != 0)
- Ty = Context.getExtVectorType(Ty, NumElts);
- E = ImpCastExprToType(E, Ty, CK_FloatingCast).get();
+ E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get();
}
}
@@ -923,12 +916,13 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
UnqualifiedId Name;
Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
E->getBeginLoc());
- ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc,
- Name, true, false);
+ ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name,
+ /*HasTrailingLParen=*/true,
+ /*IsAddressOfOperand=*/false);
if (TrapFn.isInvalid())
return ExprError();
- ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(),
+ ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(),
None, E->getEndLoc());
if (Call.isInvalid())
return ExprError();
@@ -1089,8 +1083,8 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
LHSType = S.Context.FloatTy;
return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType,
- /*convertFloat=*/!IsCompAssign,
- /*convertInt=*/ true);
+ /*ConvertFloat=*/!IsCompAssign,
+ /*ConvertInt=*/ true);
}
assert(RHSFloat);
return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType,
@@ -1250,6 +1244,93 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
return ComplexType;
}
+/// Return the rank of a given fixed point or integer type. The value itself
+/// doesn't matter, but the values must be increasing with proper increasing
+/// rank as described in N1169 4.1.1.
+static unsigned GetFixedPointRank(QualType Ty) {
+ const auto *BTy = Ty->getAs<BuiltinType>();
+ assert(BTy && "Expected a builtin type.");
+
+ switch (BTy->getKind()) {
+ case BuiltinType::ShortFract:
+ case BuiltinType::UShortFract:
+ case BuiltinType::SatShortFract:
+ case BuiltinType::SatUShortFract:
+ return 1;
+ case BuiltinType::Fract:
+ case BuiltinType::UFract:
+ case BuiltinType::SatFract:
+ case BuiltinType::SatUFract:
+ return 2;
+ case BuiltinType::LongFract:
+ case BuiltinType::ULongFract:
+ case BuiltinType::SatLongFract:
+ case BuiltinType::SatULongFract:
+ return 3;
+ case BuiltinType::ShortAccum:
+ case BuiltinType::UShortAccum:
+ case BuiltinType::SatShortAccum:
+ case BuiltinType::SatUShortAccum:
+ return 4;
+ case BuiltinType::Accum:
+ case BuiltinType::UAccum:
+ case BuiltinType::SatAccum:
+ case BuiltinType::SatUAccum:
+ return 5;
+ case BuiltinType::LongAccum:
+ case BuiltinType::ULongAccum:
+ case BuiltinType::SatLongAccum:
+ case BuiltinType::SatULongAccum:
+ return 6;
+ default:
+ if (BTy->isInteger())
+ return 0;
+ llvm_unreachable("Unexpected fixed point or integer type");
+ }
+}
+
+/// handleFixedPointConversion - Fixed point operations between fixed
+/// point types and integers or other fixed point types do not fall under
+/// usual arithmetic conversion since these conversions could result in loss
+/// of precsision (N1169 4.1.4). These operations should be calculated with
+/// the full precision of their result type (N1169 4.1.6.2.1).
+static QualType handleFixedPointConversion(Sema &S, QualType LHSTy,
+ QualType RHSTy) {
+ assert((LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) &&
+ "Expected at least one of the operands to be a fixed point type");
+ assert((LHSTy->isFixedPointOrIntegerType() ||
+ RHSTy->isFixedPointOrIntegerType()) &&
+ "Special fixed point arithmetic operation conversions are only "
+ "applied to ints or other fixed point types");
+
+ // If one operand has signed fixed-point type and the other operand has
+ // unsigned fixed-point type, then the unsigned fixed-point operand is
+ // converted to its corresponding signed fixed-point type and the resulting
+ // type is the type of the converted operand.
+ if (RHSTy->isSignedFixedPointType() && LHSTy->isUnsignedFixedPointType())
+ LHSTy = S.Context.getCorrespondingSignedFixedPointType(LHSTy);
+ else if (RHSTy->isUnsignedFixedPointType() && LHSTy->isSignedFixedPointType())
+ RHSTy = S.Context.getCorrespondingSignedFixedPointType(RHSTy);
+
+ // The result type is the type with the highest rank, whereby a fixed-point
+ // conversion rank is always greater than an integer conversion rank; if the
+ // type of either of the operands is a saturating fixedpoint type, the result
+ // type shall be the saturating fixed-point type corresponding to the type
+ // with the highest rank; the resulting value is converted (taking into
+ // account rounding and overflow) to the precision of the resulting type.
+ // Same ranks between signed and unsigned types are resolved earlier, so both
+ // types are either signed or both unsigned at this point.
+ unsigned LHSTyRank = GetFixedPointRank(LHSTy);
+ unsigned RHSTyRank = GetFixedPointRank(RHSTy);
+
+ QualType ResultTy = LHSTyRank > RHSTyRank ? LHSTy : RHSTy;
+
+ if (LHSTy->isSaturatedFixedPointType() || RHSTy->isSaturatedFixedPointType())
+ ResultTy = S.Context.getCorrespondingSaturatedType(ResultTy);
+
+ return ResultTy;
+}
+
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
/// routine returns the first non-arithmetic type found. The client is
@@ -1322,12 +1403,14 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
IsCompAssign);
+ if (LHSType->isFixedPointType() || RHSType->isFixedPointType())
+ return handleFixedPointConversion(*this, LHSType, RHSType);
+
// Finally, we have two differing integer types.
return handleIntegerConversion<doIntegralCast, doIntegralCast>
(*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
}
-
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -1446,9 +1529,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
// If we determined that the generic selection is result-dependent, don't
// try to compute the result expression.
if (IsResultDependent)
- return new (Context) GenericSelectionExpr(
- Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc,
- ContainsUnexpandedParameterPack);
+ return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, Types,
+ Exprs, DefaultLoc, RParenLoc,
+ ContainsUnexpandedParameterPack);
SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
@@ -1499,7 +1582,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
unsigned ResultIndex =
CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
- return new (Context) GenericSelectionExpr(
+ return GenericSelectionExpr::Create(
Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc,
ContainsUnexpandedParameterPack, ResultIndex);
}
@@ -1605,20 +1688,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
Diag(RemovalDiagLoc, RemovalDiag);
}
-
- QualType CharTyConst = CharTy;
- // A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
- if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
- CharTyConst.addConst();
-
- CharTyConst = Context.adjustStringLiteralBaseType(CharTyConst);
-
- // Get an array type for the string, according to C99 6.4.5. This includes
- // the nul terminator character as well as the string length for pascal
- // strings.
- QualType StrTy = Context.getConstantArrayType(
- CharTyConst, llvm::APInt(32, Literal.GetNumStringChars() + 1),
- ArrayType::Normal, 0);
+ QualType StrTy =
+ Context.getStringLiteralArrayType(CharTy, Literal.GetNumStringChars());
// Pass &StringTokLocs[0], StringTokLocs.size() to factory!
StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(),
@@ -1696,7 +1767,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
llvm_unreachable("unexpected literal operator lookup result");
}
-ExprResult
+DeclRefExpr *
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
SourceLocation Loc,
const CXXScopeSpec *SS) {
@@ -1704,36 +1775,54 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
return BuildDeclRefExpr(D, Ty, VK, NameInfo, SS);
}
+DeclRefExpr *
+Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
+ const DeclarationNameInfo &NameInfo,
+ const CXXScopeSpec *SS, NamedDecl *FoundD,
+ SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ NestedNameSpecifierLoc NNS =
+ SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc();
+ return BuildDeclRefExpr(D, Ty, VK, NameInfo, NNS, FoundD, TemplateKWLoc,
+ TemplateArgs);
+}
+
+NonOdrUseReason Sema::getNonOdrUseReasonInCurrentContext(ValueDecl *D) {
+ // A declaration named in an unevaluated operand never constitutes an odr-use.
+ if (isUnevaluatedContext())
+ return NOUR_Unevaluated;
+
+ // C++2a [basic.def.odr]p4:
+ // A variable x whose name appears as a potentially-evaluated expression e
+ // is odr-used by e unless [...] x is a reference that is usable in
+ // constant expressions.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getType()->isReferenceType() &&
+ !(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) &&
+ VD->isUsableInConstantExpressions(Context))
+ return NOUR_Constant;
+ }
+
+ // All remaining non-variable cases constitute an odr-use. For variables, we
+ // need to wait and see how the expression is used.
+ return NOUR_None;
+}
+
/// BuildDeclRefExpr - Build an expression that references a
/// declaration that does not require a closure capture.
-ExprResult
+DeclRefExpr *
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS, NamedDecl *FoundD,
+ NestedNameSpecifierLoc NNS, NamedDecl *FoundD,
+ SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo *TemplateArgs) {
bool RefersToCapturedVariable =
isa<VarDecl>(D) &&
NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
- DeclRefExpr *E;
- if (isa<VarTemplateSpecializationDecl>(D)) {
- VarTemplateSpecializationDecl *VarSpec =
- cast<VarTemplateSpecializationDecl>(D);
-
- E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context)
- : NestedNameSpecifierLoc(),
- VarSpec->getTemplateKeywordLoc(), D,
- RefersToCapturedVariable, NameInfo.getLoc(), Ty, VK,
- FoundD, TemplateArgs);
- } else {
- assert(!TemplateArgs && "No template arguments for non-variable"
- " template specialization references");
- E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context)
- : NestedNameSpecifierLoc(),
- SourceLocation(), D, RefersToCapturedVariable,
- NameInfo, Ty, VK, FoundD);
- }
-
+ DeclRefExpr *E = DeclRefExpr::Create(
+ Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
+ VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
MarkDeclRefReferenced(E);
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
@@ -1828,11 +1917,10 @@ static void emitEmptyLookupTypoDiagnostic(
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
-bool
-Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- std::unique_ptr<CorrectionCandidateCallback> CCC,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- ArrayRef<Expr *> Args, TypoExpr **Out) {
+bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
+ CorrectionCandidateCallback &CCC,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
+ ArrayRef<Expr *> Args, TypoExpr **Out) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1921,7 +2009,7 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
assert(!ExplicitTemplateArgs &&
"Diagnosing an empty lookup with explicit template args!");
*Out = CorrectTypoDelayed(
- R.getLookupNameInfo(), R.getLookupKind(), S, &SS, std::move(CCC),
+ R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC,
[=](const TypoCorrection &TC) {
emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
diagnostic, diagnostic_suggest);
@@ -1929,9 +2017,9 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
nullptr, CTK_ErrorRecovery);
if (*Out)
return true;
- } else if (S && (Corrected =
- CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S,
- &SS, std::move(CCC), CTK_ErrorRecovery))) {
+ } else if (S &&
+ (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
+ S, &SS, CCC, CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@@ -1988,8 +2076,9 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// is in the wrong place to recover. Suggest the typo
// correction, but don't make it a fix-it since we're not going
// to recover well anyway.
- AcceptableWithoutRecovery =
- isa<TypeDecl>(UnderlyingND) || isa<ObjCInterfaceDecl>(UnderlyingND);
+ AcceptableWithoutRecovery = isa<TypeDecl>(UnderlyingND) ||
+ getAsTypeTemplateDecl(UnderlyingND) ||
+ isa<ObjCInterfaceDecl>(UnderlyingND);
} else {
// FIXME: We found a keyword. Suggest it, but don't provide a fix-it
// because we aren't able to recover.
@@ -2062,7 +2151,7 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
return CXXDependentScopeMemberExpr::Create(
Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true,
/*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc,
- /*FirstQualifierInScope=*/nullptr, NameInfo, TemplateArgs);
+ /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs);
}
// Synthesize a fake NNS that points to the derived class. This will
@@ -2080,7 +2169,7 @@ ExprResult
Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
SourceLocation TemplateKWLoc, UnqualifiedId &Id,
bool HasTrailingLParen, bool IsAddressOfOperand,
- std::unique_ptr<CorrectionCandidateCallback> CCC,
+ CorrectionCandidateCallback *CCC,
bool IsInlineAsmIdentifier, Token *KeywordReplacement) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
@@ -2144,8 +2233,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
bool MemberOfUnknownSpecialization;
+ AssumedTemplateKind AssumedTemplate;
if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
- MemberOfUnknownSpecialization, TemplateKWLoc))
+ MemberOfUnknownSpecialization, TemplateKWLoc,
+ &AssumedTemplate))
return ExprError();
if (MemberOfUnknownSpecialization ||
@@ -2202,9 +2293,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
TypoExpr *TE = nullptr;
- auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>(
- II, SS.isValid() ? SS.getScopeRep() : nullptr);
- DefaultValidator->IsAddressOfOperand = IsAddressOfOperand;
+ DefaultFilterCCC DefaultValidator(II, SS.isValid() ? SS.getScopeRep()
+ : nullptr);
+ DefaultValidator.IsAddressOfOperand = IsAddressOfOperand;
assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) &&
"Typo correction callback misconfigured");
if (CCC) {
@@ -2216,9 +2307,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for
// a template name, but we happen to have always already looked up the name
// before we get here if it must be a template name.
- if (DiagnoseEmptyLookup(S, SS, R,
- CCC ? std::move(CCC) : std::move(DefaultValidator),
- nullptr, None, &TE)) {
+ if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
+ None, &TE)) {
if (TE && KeywordReplacement) {
auto &State = getTypoExprState(TE);
auto BestTC = State.Consumer->getNextCorrection();
@@ -2472,8 +2562,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
CXXScopeSpec SelfScopeSpec;
SourceLocation TemplateKWLoc;
- ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc,
- SelfName, false, false);
+ ExprResult SelfExpr =
+ ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
+ /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
if (SelfExpr.isInvalid())
return ExprError();
@@ -2497,11 +2589,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
getCurFunction()->recordUseOfWeak(Result);
}
- if (getLangOpts().ObjCAutoRefCount) {
- if (CurContext->isClosure())
- Diag(Loc, diag::warn_implicitly_retains_self)
- << FixItHint::CreateInsertion(Loc, "self->");
- }
+ if (getLangOpts().ObjCAutoRefCount)
+ if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
+ ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
return Result;
}
@@ -2572,10 +2662,15 @@ Sema::PerformObjectMemberConversion(Expr *From,
bool PointerConversions = false;
if (isa<FieldDecl>(Member)) {
DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD));
+ auto FromPtrType = FromType->getAs<PointerType>();
+ DestRecordType = Context.getAddrSpaceQualType(
+ DestRecordType, FromPtrType
+ ? FromType->getPointeeType().getAddressSpace()
+ : FromType.getAddressSpace());
- if (FromType->getAs<PointerType>()) {
+ if (FromPtrType) {
DestType = Context.getPointerType(DestRecordType);
- FromRecordType = FromType->getPointeeType();
+ FromRecordType = FromPtrType->getPointeeType();
PointerConversions = true;
} else {
DestType = DestRecordType;
@@ -2905,7 +3000,6 @@ ExprResult Sema::BuildDeclarationNameExpr(
// These shouldn't make it here.
case Decl::ObjCAtDefsField:
- case Decl::ObjCIvar:
llvm_unreachable("forming non-member reference to ivar?");
// Enum constants are always r-values and never references.
@@ -2913,6 +3007,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::EnumConstant:
case Decl::UnresolvedUsingValue:
case Decl::OMPDeclareReduction:
+ case Decl::OMPDeclareMapper:
valueKind = VK_RValue;
break;
@@ -2922,6 +3017,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
// exist in the high-level semantics.
case Decl::Field:
case Decl::IndirectField:
+ case Decl::ObjCIvar:
assert(getLangOpts().CPlusPlus &&
"building reference to field in C?");
@@ -2986,9 +3082,11 @@ ExprResult Sema::BuildDeclarationNameExpr(
// FIXME: Support lambda-capture of BindingDecls, once CWG actually
// decides how that's supposed to work.
auto *BD = cast<BindingDecl>(VD);
- if (BD->getDeclContext()->isFunctionOrMethod() &&
- BD->getDeclContext() != CurContext)
- diagnoseUncapturableValueReference(*this, Loc, BD, CurContext);
+ if (BD->getDeclContext() != CurContext) {
+ auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
+ if (DD && DD->hasLocalStorage())
+ diagnoseUncapturableValueReference(*this, Loc, BD, CurContext);
+ }
break;
}
@@ -3066,6 +3164,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
}
return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
+ /*FIXME: TemplateKWLoc*/ SourceLocation(),
TemplateArgs);
}
}
@@ -3975,32 +4074,11 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
// Unknown size indication requires no size computation.
// Otherwise, evaluate and record it.
- if (auto Size = VAT->getSizeExpr()) {
- if (!CSI->isVLATypeCaptured(VAT)) {
- RecordDecl *CapRecord = nullptr;
- if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
- CapRecord = LSI->Lambda;
- } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- CapRecord = CRSI->TheRecordDecl;
- }
- if (CapRecord) {
- auto ExprLoc = Size->getExprLoc();
- auto SizeType = Context.getSizeType();
- // Build the non-static data member.
- auto Field =
- FieldDecl::Create(Context, CapRecord, ExprLoc, ExprLoc,
- /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr,
- /*BW*/ nullptr, /*Mutable*/ false,
- /*InitStyle*/ ICIS_NoInit);
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- Field->setCapturedVLAType(VAT);
- CapRecord->addDecl(Field);
-
- CSI->addVLATypeCapture(ExprLoc, SizeType);
- }
- }
- }
+ auto Size = VAT->getSizeExpr();
+ if (Size && !CSI->isVLATypeCaptured(VAT) &&
+ (isa<CapturedRegionScopeInfo>(CSI) || isa<LambdaScopeInfo>(CSI)))
+ CSI->addVLATypeCapture(Size->getExprLoc(), VAT, Context.getSizeType());
+
T = VAT->getElementType();
break;
}
@@ -4014,6 +4092,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::Attributed:
case Type::SubstTemplateTypeParm:
case Type::PackExpansion:
+ case Type::MacroQualified:
// Keep walking after single level desugaring.
T = T.getSingleStepDesugaredType(Context);
break;
@@ -4658,6 +4737,33 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
!ResultType.isCForbiddenLValueType());
+ if (LHSExp->IgnoreParenImpCasts()->getType()->isVariablyModifiedType() &&
+ FunctionScopes.size() > 1) {
+ if (auto *TT =
+ LHSExp->IgnoreParenImpCasts()->getType()->getAs<TypedefType>()) {
+ 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))
+ DC = LSI->CallOperator;
+ else if (auto *CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI))
+ DC = CRSI->TheCapturedDecl;
+ else if (auto *BSI = dyn_cast<BlockScopeInfo>(CSI))
+ DC = BSI->TheDecl;
+ if (DC) {
+ if (DC->containsDecl(TT->getDecl()))
+ break;
+ captureVariablyModifiedType(
+ Context, LHSExp->IgnoreParenImpCasts()->getType(), CSI);
+ }
+ }
+ }
+ }
+
return new (Context)
ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc);
}
@@ -4778,6 +4884,8 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// We already type-checked the argument, so we know it works.
// Just mark all of the declarations in this potentially-evaluated expression
// as being "referenced".
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
/*SkipLocalVariables=*/true);
return false;
@@ -4787,7 +4895,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD, ParmVarDecl *Param) {
if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
return ExprError();
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param);
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
}
Sema::VariadicCallType
@@ -4810,7 +4918,7 @@ Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto,
}
namespace {
-class FunctionCallCCC : public FunctionCallFilterCCC {
+class FunctionCallCCC final : public FunctionCallFilterCCC {
public:
FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName,
unsigned NumArgs, MemberExpr *ME)
@@ -4826,6 +4934,10 @@ public:
return FunctionCallFilterCCC::ValidateCandidate(candidate);
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<FunctionCallCCC>(*this);
+ }
+
private:
const IdentifierInfo *const FunctionName;
};
@@ -4838,11 +4950,10 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
DeclarationName FuncName = FDecl->getDeclName();
SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getBeginLoc();
+ FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME);
if (TypoCorrection Corrected = S.CorrectTypo(
DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName,
- S.getScopeForContext(S.CurContext), nullptr,
- llvm::make_unique<FunctionCallCCC>(S, FuncName.getAsIdentifierInfo(),
- Args.size(), ME),
+ S.getScopeForContext(S.CurContext), nullptr, CCC,
Sema::CTK_ErrorRecovery)) {
if (NamedDecl *ND = Corrected.getFoundDecl()) {
if (Corrected.isOverloaded()) {
@@ -5049,8 +5160,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
} else {
assert(Param && "can't use default arguments without a known callee");
- ExprResult ArgExpr =
- BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
+ ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
if (ArgExpr.isInvalid())
return true;
@@ -5140,15 +5250,29 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc,
return;
const ConstantArrayType *ArgCAT =
- Context.getAsConstantArrayType(ArgExpr->IgnoreParenImpCasts()->getType());
+ Context.getAsConstantArrayType(ArgExpr->IgnoreParenCasts()->getType());
if (!ArgCAT)
return;
- if (ArgCAT->getSize().ult(CAT->getSize())) {
+ if (getASTContext().hasSameUnqualifiedType(CAT->getElementType(),
+ ArgCAT->getElementType())) {
+ if (ArgCAT->getSize().ult(CAT->getSize())) {
+ Diag(CallLoc, diag::warn_static_array_too_small)
+ << ArgExpr->getSourceRange()
+ << (unsigned)ArgCAT->getSize().getZExtValue()
+ << (unsigned)CAT->getSize().getZExtValue() << 0;
+ DiagnoseCalleeStaticArrayParam(*this, Param);
+ }
+ return;
+ }
+
+ Optional<CharUnits> ArgSize =
+ getASTContext().getTypeSizeInCharsIfKnown(ArgCAT);
+ Optional<CharUnits> ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT);
+ if (ArgSize && ParmSize && *ArgSize < *ParmSize) {
Diag(CallLoc, diag::warn_static_array_too_small)
- << ArgExpr->getSourceRange()
- << (unsigned) ArgCAT->getSize().getZExtValue()
- << (unsigned) CAT->getSize().getZExtValue();
+ << ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity()
+ << (unsigned)ParmSize->getQuantity() << 1;
DiagnoseCalleeStaticArrayParam(*this, Param);
}
}
@@ -5236,7 +5360,7 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) {
/// FunctionDecl is returned.
/// TODO: Handle pointer return types.
static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
- const FunctionDecl *FDecl,
+ FunctionDecl *FDecl,
MultiExprArg ArgExprs) {
QualType DeclType = FDecl->getType();
@@ -5284,7 +5408,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
FunctionProtoType::ExtProtoInfo EPI;
QualType OverloadTy = Context.getFunctionType(FT->getReturnType(),
OverloadParams, EPI);
- DeclContext *Parent = Context.getTranslationUnitDecl();
+ DeclContext *Parent = FDecl->getParent();
FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent,
FDecl->getLocation(),
FDecl->getLocation(),
@@ -5415,10 +5539,33 @@ tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
}
}
-/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
+ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
+ MultiExprArg ArgExprs, SourceLocation RParenLoc,
+ Expr *ExecConfig) {
+ ExprResult Call =
+ BuildCallExpr(Scope, Fn, LParenLoc, ArgExprs, RParenLoc, ExecConfig);
+ if (Call.isInvalid())
+ return Call;
+
+ // Diagnose uses of the C++20 "ADL-only template-id call" feature in earlier
+ // language modes.
+ if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn)) {
+ if (ULE->hasExplicitTemplateArgs() &&
+ ULE->decls_begin() == ULE->decls_end()) {
+ Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_adl_only_template_id
+ : diag::ext_adl_only_template_id)
+ << ULE->getName();
+ }
+ }
+
+ return Call;
+}
+
+/// BuildCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
-ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
+ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig) {
// Since this might be a postfix expression, get rid of ParenListExprs.
@@ -5521,8 +5668,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
}
}
- if (isa<DeclRefExpr>(NakedFn)) {
- NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(NakedFn)) {
+ NDecl = DRE->getDecl();
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(NDecl);
if (FDecl && FDecl->getBuiltinID()) {
@@ -5534,7 +5681,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
NDecl = FDecl;
Fn = DeclRefExpr::Create(
Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false,
- SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl);
+ SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl,
+ nullptr, DRE->isNonOdrUse());
}
}
} else if (isa<MemberExpr>(NakedFn))
@@ -5646,28 +5794,29 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// CheckBuiltinFunctionCall below just after creation of the call expression.
const FunctionType *FuncT = nullptr;
if (!BuiltinID || !Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) {
- retry:
+ retry:
if (const PointerType *PT = Fn->getType()->getAs<PointerType>()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
// have type pointer to function".
FuncT = PT->getPointeeType()->getAs<FunctionType>();
if (!FuncT)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
- << Fn->getType() << Fn->getSourceRange());
+ << Fn->getType() << Fn->getSourceRange());
} else if (const BlockPointerType *BPT =
- Fn->getType()->getAs<BlockPointerType>()) {
+ Fn->getType()->getAs<BlockPointerType>()) {
FuncT = BPT->getPointeeType()->castAs<FunctionType>();
} else {
// Handle calls to expressions of unknown-any type.
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn);
- if (rewrite.isInvalid()) return ExprError();
+ if (rewrite.isInvalid())
+ return ExprError();
Fn = rewrite.get();
goto retry;
}
- return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
- << Fn->getType() << Fn->getSourceRange());
+ return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
+ << Fn->getType() << Fn->getSourceRange());
}
}
@@ -5690,18 +5839,36 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
}
if (!getLangOpts().CPlusPlus) {
+ // Forget about the nulled arguments since typo correction
+ // do not handle them well.
+ TheCall->shrinkNumArgs(Args.size());
// C cannot always handle TypoExpr nodes in builtin calls and direct
// function calls as their argument checking don't necessarily handle
// dependent types properly, so make sure any TypoExprs have been
// dealt with.
ExprResult Result = CorrectDelayedTyposInExpr(TheCall);
if (!Result.isUsable()) return ExprError();
+ CallExpr *TheOldCall = TheCall;
TheCall = dyn_cast<CallExpr>(Result.get());
+ bool CorrectedTypos = TheCall != TheOldCall;
if (!TheCall) return Result;
- // TheCall at this point has max(Args.size(), NumParams) arguments,
- // with extra arguments nulled. We don't want to introduce nulled
- // arguments in Args and so we only take the first Args.size() arguments.
- Args = llvm::makeArrayRef(TheCall->getArgs(), Args.size());
+ Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs());
+
+ // A new call expression node was created if some typos were corrected.
+ // However it may not have been constructed with enough storage. In this
+ // case, rebuild the node with enough storage. The waste of space is
+ // immaterial since this only happens when some typos were corrected.
+ if (CorrectedTypos && Args.size() < NumParams) {
+ if (Config)
+ TheCall = CUDAKernelCallExpr::Create(
+ Context, Fn, cast<CallExpr>(Config), Args, ResultTy, VK_RValue,
+ RParenLoc, NumParams);
+ else
+ TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue,
+ RParenLoc, NumParams, UsesADL);
+ }
+ // We can now handle the nulled arguments for the default arguments.
+ TheCall->setNumArgsUnsafe(std::max<unsigned>(Args.size(), NumParams));
}
// Bail out early if calling a builtin with custom type checking.
@@ -5805,6 +5972,8 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (CheckFunctionCall(FDecl, TheCall, Proto))
return ExprError();
+ checkFortifiedBuiltinMemoryFunction(FDecl, TheCall);
+
if (BuiltinID)
return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall);
} else if (NDecl) {
@@ -5897,7 +6066,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ILE->setInit(i, ConstantExpr::Create(Context, Init));
}
- Expr *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
+ auto *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
VK, LiteralExpr, isFileScope);
if (isFileScope) {
if (!LiteralExpr->isTypeDependent() &&
@@ -5915,6 +6084,19 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
return ExprError();
}
+ // Compound literals that have automatic storage duration are destroyed at
+ // the end of the scope. Emit diagnostics if it is or contains a C union type
+ // that is non-trivial to destruct.
+ if (!isFileScope)
+ if (E->getType().hasNonTrivialToPrimitiveDestructCUnion())
+ checkNonTrivialCUnion(E->getType(), E->getExprLoc(),
+ NTCUC_CompoundLiteral, NTCUK_Destruct);
+
+ if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ E->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnionInInitializer(E->getInitializer(),
+ E->getInitializer()->getExprLoc());
+
return MaybeBindToTemporary(E);
}
@@ -6031,6 +6213,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_Bool:
return CK_FixedPointToBoolean;
case Type::STK_Integral:
+ return CK_FixedPointToIntegral;
case Type::STK_Floating:
case Type::STK_IntegralComplex:
case Type::STK_FloatingComplex:
@@ -6075,10 +6258,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
case Type::STK_FixedPoint:
- Diag(Src.get()->getExprLoc(),
- diag::err_unimplemented_conversion_with_fixed_point_type)
- << SrcTy;
- return CK_IntegralCast;
+ return CK_IntegralToFixedPoint;
}
llvm_unreachable("Should have returned before this");
@@ -7128,10 +7308,10 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// GCC compatibility: soften pointer/integer mismatch. Note that
// null pointers have been filtered out by this point.
if (checkPointerIntegerMismatch(*this, LHS, RHS.get(), QuestionLoc,
- /*isIntFirstExpr=*/true))
+ /*IsIntFirstExpr=*/true))
return RHSTy;
if (checkPointerIntegerMismatch(*this, RHS, LHS.get(), QuestionLoc,
- /*isIntFirstExpr=*/false))
+ /*IsIntFirstExpr=*/false))
return LHSTy;
// Emit a better diagnostic if one of the expressions is a null pointer
@@ -7600,9 +7780,9 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
}
if (!lhq.compatiblyIncludes(rhq)) {
- // Treat address-space mismatches as fatal. TODO: address subspaces
+ // Treat address-space mismatches as fatal.
if (!lhq.isAddressSpaceSupersetOf(rhq))
- ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
+ return Sema::IncompatiblePointerDiscardsQualifiers;
// It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
@@ -7675,8 +7855,22 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
// level of indirection, this must be the issue.
if (isa<PointerType>(lhptee) && isa<PointerType>(rhptee)) {
do {
- lhptee = cast<PointerType>(lhptee)->getPointeeType().getTypePtr();
- rhptee = cast<PointerType>(rhptee)->getPointeeType().getTypePtr();
+ std::tie(lhptee, lhq) =
+ cast<PointerType>(lhptee)->getPointeeType().split().asPair();
+ std::tie(rhptee, rhq) =
+ cast<PointerType>(rhptee)->getPointeeType().split().asPair();
+
+ // Inconsistent address spaces at this point is invalid, even if the
+ // address spaces would be compatible.
+ // FIXME: This doesn't catch address space mismatches for pointers of
+ // different nesting levels, like:
+ // __local int *** a;
+ // int ** b = a;
+ // It's not clear how to actually determine when such pointers are
+ // invalidly incompatible.
+ if (lhq.getAddressSpace() != rhq.getAddressSpace())
+ return Sema::IncompatibleNestedPointerAddressSpaceMismatch;
+
} while (isa<PointerType>(lhptee) && isa<PointerType>(rhptee));
if (lhptee == rhptee)
@@ -8911,7 +9105,7 @@ static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
bool IsCompAssign, bool IsDiv) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType())
@@ -8935,7 +9129,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
QualType Sema::CheckRemainderOperands(
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
@@ -9224,7 +9418,7 @@ static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc,
QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, BinaryOperatorKind Opc,
QualType* CompLHSTy) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
@@ -9318,7 +9512,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
QualType* CompLHSTy) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
@@ -9464,9 +9658,11 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
return;
// When left shifting an ICE which is signed, we can check for overflow which
- // according to C++ has undefined behavior ([expr.shift] 5.8/2). Unsigned
- // integers have defined behavior modulo one more than the maximum value
- // representable in the result type, so never warn for those.
+ // according to C++ standards prior to C++2a has undefined behavior
+ // ([expr.shift] 5.8/2). Unsigned integers have defined behavior modulo one
+ // more than the maximum value representable in the result type, so never
+ // warn for those. (FIXME: Unsigned left-shift overflow in a constant
+ // expression is still probably a bug.)
Expr::EvalResult LHSResult;
if (LHS.get()->isValueDependent() ||
LHSType->hasUnsignedIntegerRepresentation() ||
@@ -9475,8 +9671,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
llvm::APSInt Left = LHSResult.Val.getInt();
// If LHS does not have a signed type and non-negative value
- // then, the behavior is undefined. Warn about it.
- if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined()) {
+ // then, the behavior is undefined before C++2a. Warn about it.
+ if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined() &&
+ !S.getLangOpts().CPlusPlus2a) {
S.DiagRuntimeBehavior(Loc, LHS.get(),
S.PDiag(diag::warn_shift_lhs_negative)
<< LHS.get()->getSourceRange());
@@ -9603,7 +9800,7 @@ static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS,
QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, BinaryOperatorKind Opc,
bool IsCompAssign) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
// Vector shifts promote their scalar inputs to vector type.
if (LHS.get()->getType()->isVectorType() ||
@@ -9772,7 +9969,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
Selector IsEqualSel = S.NSAPIObj->getIsEqualSelector();
ObjCMethodDecl *Method = S.LookupMethodInObjectType(IsEqualSel,
InterfaceType,
- /*instance=*/true);
+ /*IsInstance=*/true);
if (!Method) {
if (Type->isObjCIdType()) {
// For 'id', just check the global pool.
@@ -9781,7 +9978,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
} else {
// Check protocols.
Method = S.LookupMethodInQualifiedType(IsEqualSel, Type,
- /*instance=*/true);
+ /*IsInstance=*/true);
}
}
@@ -10281,7 +10478,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/true);
// Handle vector comparisons separately.
if (LHS.get()->getType()->isVectorType() ||
@@ -10663,7 +10860,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return computeResultTy();
}
- if (getLangOpts().OpenCLVersion >= 200) {
+ if (getLangOpts().OpenCLVersion >= 200 || getLangOpts().OpenCLCPlusPlus) {
if (LHSType->isClkEventT() && RHSType->isClkEventT()) {
return computeResultTy();
}
@@ -10776,7 +10973,7 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (vType.isNull())
return InvalidOperands(Loc, LHS, RHS);
if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
- vType->hasFloatingRepresentation())
+ !getLangOpts().OpenCLCPlusPlus && vType->hasFloatingRepresentation())
return InvalidOperands(Loc, LHS, RHS);
// FIXME: The check for C++ here is for GCC compatibility. GCC rejects the
// usage of the logical operators && and || with vectors in C. This
@@ -10791,7 +10988,7 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
- checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
+ checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
bool IsCompAssign =
Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign;
@@ -12311,6 +12508,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
}
}
+ // Diagnose operations on the unsupported types for OpenMP device compilation.
+ if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) {
+ if (Opc != BO_Assign && Opc != BO_Comma) {
+ checkOpenMPDeviceExpr(LHSExpr);
+ checkOpenMPDeviceExpr(RHSExpr);
+ }
+ }
+
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@@ -12322,6 +12527,29 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (!ResultTy.isNull()) {
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true);
DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc);
+
+ // Avoid copying a block to the heap if the block is assigned to a local
+ // auto variable that is declared in the same scope as the block. This
+ // optimization is unsafe if the local variable is declared in an outer
+ // scope. For example:
+ //
+ // BlockTy b;
+ // {
+ // b = ^{...};
+ // }
+ // // It is unsafe to invoke the block here if it wasn't copied to the
+ // // heap.
+ // b();
+
+ if (auto *BE = dyn_cast<BlockExpr>(RHS.get()->IgnoreParens()))
+ if (auto *DRE = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens()))
+ if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VD->hasLocalStorage() && getCurScope()->isDeclScope(VD))
+ BE->getBlockDecl()->setCanAvoidCopyToHeap();
+
+ if (LHS.get()->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(LHS.get()->getType(), LHS.get()->getExprLoc(),
+ NTCUC_Assignment, NTCUK_Copy);
}
RecordModifiableNonNullParam(*this, LHS.get());
break;
@@ -12887,6 +13115,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< Input.get()->getSourceRange());
}
}
+ // Diagnose operations on the unsupported types for OpenMP device compilation.
+ if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) {
+ if (UnaryOperator::isIncrementDecrementOp(Opc) ||
+ UnaryOperator::isArithmeticOp(Opc))
+ checkOpenMPDeviceExpr(InputExpr);
+ }
+
switch (Opc) {
case UO_PreInc:
case UO_PreDec:
@@ -13005,7 +13240,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
} else if (resultType->isExtVectorType()) {
if (Context.getLangOpts().OpenCL &&
- Context.getLangOpts().OpenCLVersion < 120) {
+ Context.getLangOpts().OpenCLVersion < 120 &&
+ !Context.getLangOpts().OpenCLCPlusPlus) {
// OpenCL v1.1 6.3.h: The logical operator not (!) does not
// operate on vector float types.
QualType T = resultType->getAs<ExtVectorType>()->getElementType();
@@ -13180,29 +13416,6 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
Context.getPointerType(Context.VoidTy));
}
-/// Given the last statement in a statement-expression, check whether
-/// the result is a producing expression (like a call to an
-/// ns_returns_retained function) and, if so, rebuild it to hoist the
-/// release out of the full-expression. Otherwise, return null.
-/// Cannot fail.
-static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) {
- // Should always be wrapped with one of these.
- ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement);
- if (!cleanups) return nullptr;
-
- ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
- if (!cast || cast->getCastKind() != CK_ARCConsumeObject)
- return nullptr;
-
- // Splice out the cast. This shouldn't modify any interesting
- // features of the statement.
- Expr *producer = cast->getSubExpr();
- assert(producer->getType() == cast->getType());
- assert(producer->getValueKind() == cast->getValueKind());
- cleanups->setSubExpr(producer);
- return cleanups;
-}
-
void Sema::ActOnStartStmtExpr() {
PushExpressionEvaluationContext(ExprEvalContexts.back().Context);
}
@@ -13236,47 +13449,12 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
QualType Ty = Context.VoidTy;
bool StmtExprMayBindToTemp = false;
if (!Compound->body_empty()) {
- Stmt *LastStmt = Compound->body_back();
- LabelStmt *LastLabelStmt = nullptr;
- // If LastStmt is a label, skip down through into the body.
- while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) {
- LastLabelStmt = Label;
- LastStmt = Label->getSubStmt();
- }
-
- if (Expr *LastE = dyn_cast<Expr>(LastStmt)) {
- // Do function/array conversion on the last expression, but not
- // lvalue-to-rvalue. However, initialize an unqualified type.
- ExprResult LastExpr = DefaultFunctionArrayConversion(LastE);
- if (LastExpr.isInvalid())
- return ExprError();
- Ty = LastExpr.get()->getType().getUnqualifiedType();
-
- if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) {
- // In ARC, if the final expression ends in a consume, splice
- // the consume out and bind it later. In the alternate case
- // (when dealing with a retainable type), the result
- // initialization will create a produce. In both cases the
- // result will be +1, and we'll need to balance that out with
- // a bind.
- if (Expr *rebuiltLastStmt
- = maybeRebuildARCConsumingStmt(LastExpr.get())) {
- LastExpr = rebuiltLastStmt;
- } else {
- LastExpr = PerformCopyInitialization(
- InitializedEntity::InitializeStmtExprResult(LPLoc, Ty),
- SourceLocation(), LastExpr);
- }
-
- if (LastExpr.isInvalid())
- return ExprError();
- if (LastExpr.get() != nullptr) {
- if (!LastLabelStmt)
- Compound->setLastStmt(LastExpr.get());
- else
- LastLabelStmt->setSubStmt(LastExpr.get());
- StmtExprMayBindToTemp = true;
- }
+ // For GCC compatibility we get the last Stmt excluding trailing NullStmts.
+ if (const auto *LastStmt =
+ dyn_cast<ValueStmt>(Compound->getStmtExprResult())) {
+ if (const Expr *Value = LastStmt->getExprStmt()) {
+ StmtExprMayBindToTemp = true;
+ Ty = Value->getType();
}
}
}
@@ -13289,6 +13467,37 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
return ResStmtExpr;
}
+ExprResult Sema::ActOnStmtExprResult(ExprResult ER) {
+ if (ER.isInvalid())
+ return ExprError();
+
+ // Do function/array conversion on the last expression, but not
+ // lvalue-to-rvalue. However, initialize an unqualified type.
+ ER = DefaultFunctionArrayConversion(ER.get());
+ if (ER.isInvalid())
+ return ExprError();
+ Expr *E = ER.get();
+
+ if (E->isTypeDependent())
+ return E;
+
+ // In ARC, if the final expression ends in a consume, splice
+ // the consume out and bind it later. In the alternate case
+ // (when dealing with a retainable type), the result
+ // initialization will create a produce. In both cases the
+ // result will be +1, and we'll need to balance that out with
+ // a bind.
+ auto *Cast = dyn_cast<ImplicitCastExpr>(E);
+ if (Cast && Cast->getCastKind() == CK_ARCConsumeObject)
+ return Cast->getSubExpr();
+
+ // FIXME: Provide a better location for the initialization.
+ return PerformCopyInitialization(
+ InitializedEntity::InitializeStmtExprResult(
+ E->getBeginLoc(), E->getType().getUnqualifiedType()),
+ SourceLocation(), E);
+}
+
ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
TypeSourceInfo *TInfo,
ArrayRef<OffsetOfComponent> Components,
@@ -13573,8 +13782,8 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
// Look for an explicit signature in that function type.
FunctionProtoTypeLoc ExplicitSignature;
- if ((ExplicitSignature =
- Sig->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>())) {
+ if ((ExplicitSignature = Sig->getTypeLoc()
+ .getAsAdjusted<FunctionProtoTypeLoc>())) {
// Check whether that explicit signature was synthesized by
// GetTypeForDeclarator. If so, don't save that as part of the
@@ -13691,8 +13900,6 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (BSI->HasImplicitReturnType)
deduceClosureReturnType(*BSI);
- PopDeclContext();
-
QualType RetTy = Context.VoidTy;
if (!BSI->ReturnType.isNull())
RetTy = BSI->ReturnType;
@@ -13700,18 +13907,6 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
bool NoReturn = BD->hasAttr<NoReturnAttr>();
QualType BlockTy;
- // Set the captured variables on the block.
- // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
- SmallVector<BlockDecl::Capture, 4> Captures;
- for (Capture &Cap : BSI->Captures) {
- if (Cap.isThisCapture())
- continue;
- BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
- Cap.isNested(), Cap.getInitExpr());
- Captures.push_back(NewCap);
- }
- BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0);
-
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>();
@@ -13767,9 +13962,85 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
!BD->isDependentContext())
computeNRVO(Body, BSI);
- BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy);
+ if (RetTy.hasNonTrivialToPrimitiveDestructCUnion() ||
+ RetTy.hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(RetTy, BD->getCaretLocation(), NTCUC_FunctionReturn,
+ NTCUK_Destruct|NTCUK_Copy);
+
+ PopDeclContext();
+
+ // Pop the block scope now but keep it alive to the end of this function.
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
- PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result);
+ PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy);
+
+ // Set the captured variables on the block.
+ SmallVector<BlockDecl::Capture, 4> Captures;
+ for (Capture &Cap : BSI->Captures) {
+ if (Cap.isInvalid() || Cap.isThisCapture())
+ continue;
+
+ VarDecl *Var = Cap.getVariable();
+ Expr *CopyExpr = nullptr;
+ if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) {
+ if (const RecordType *Record =
+ Cap.getCaptureType()->getAs<RecordType>()) {
+ // The capture logic needs the destructor, so make sure we mark it.
+ // Usually this is unnecessary because most local variables have
+ // their destructors marked at declaration time, but parameters are
+ // an exception because it's technically only the call site that
+ // actually requires the destructor.
+ if (isa<ParmVarDecl>(Var))
+ FinalizeVarWithDestructor(Var, Record);
+
+ // Enter a separate potentially-evaluated context while building block
+ // initializers to isolate their cleanups from those of the block
+ // itself.
+ // FIXME: Is this appropriate even when the block itself occurs in an
+ // unevaluated operand?
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated);
+
+ SourceLocation Loc = Cap.getLocation();
+
+ ExprResult Result = BuildDeclarationNameExpr(
+ CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
+
+ // According to the blocks spec, the capture of a variable from
+ // the stack requires a const copy constructor. This is not true
+ // of the copy/move done to move a __block variable to the heap.
+ if (!Result.isInvalid() &&
+ !Result.get()->getType().isConstQualified()) {
+ Result = ImpCastExprToType(Result.get(),
+ Result.get()->getType().withConst(),
+ CK_NoOp, VK_LValue);
+ }
+
+ if (!Result.isInvalid()) {
+ Result = PerformCopyInitialization(
+ InitializedEntity::InitializeBlock(Var->getLocation(),
+ Cap.getCaptureType(), false),
+ Loc, Result.get());
+ }
+
+ // Build a full-expression copy expression if initialization
+ // succeeded and used a non-trivial constructor. Recover from
+ // errors by pretending that the copy isn't necessary.
+ if (!Result.isInvalid() &&
+ !cast<CXXConstructExpr>(Result.get())->getConstructor()
+ ->isTrivial()) {
+ Result = MaybeCreateExprWithCleanups(Result);
+ CopyExpr = Result.get();
+ }
+ }
+ }
+
+ BlockDecl::Capture NewCap(Var, Cap.isBlockCapture(), Cap.isNested(),
+ CopyExpr);
+ Captures.push_back(NewCap);
+ }
+ BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0);
+
+ BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy);
// If the block isn't obviously global, i.e. it captures anything at
// all, then we need to do a few things in the surrounding context:
@@ -13817,6 +14088,11 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
}
}
+ // NVPTX does not support va_arg expression.
+ if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
+ Context.getTargetInfo().getTriple().isNVPTX())
+ targetDiag(E->getBeginLoc(), 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.)
@@ -13929,6 +14205,20 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return new (Context) GNUNullExpr(Ty, TokenLoc);
}
+ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind,
+ SourceLocation BuiltinLoc,
+ SourceLocation RPLoc) {
+ return BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, CurContext);
+}
+
+ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
+ SourceLocation BuiltinLoc,
+ SourceLocation RPLoc,
+ DeclContext *ParentContext) {
+ return new (Context)
+ SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext);
+}
+
bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
bool Diagnose) {
if (!getLangOpts().ObjC)
@@ -14079,6 +14369,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleNestedPointerQualifiers:
DiagKind = diag::ext_nested_pointer_qualifier_mismatch;
break;
+ case IncompatibleNestedPointerAddressSpaceMismatch:
+ DiagKind = diag::err_typecheck_incompatible_nested_address_space;
+ break;
case IntToBlockPointer:
DiagKind = diag::err_int_to_block_pointer;
break;
@@ -14300,14 +14593,13 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
return ExprError();
}
- if (!isa<ConstantExpr>(E))
- E = ConstantExpr::Create(Context, E);
-
// Circumvent ICE checking in C++11 to avoid evaluating the expression twice
// in the non-ICE case.
if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) {
if (Result)
*Result = E->EvaluateKnownConstIntCheckOverflow(Context);
+ if (!isa<ConstantExpr>(E))
+ E = ConstantExpr::Create(Context, E);
return E;
}
@@ -14317,8 +14609,12 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// Try to evaluate the expression, and produce diagnostics explaining why it's
// not a constant expression as a side-effect.
- bool Folded = E->EvaluateAsRValue(EvalResult, Context) &&
- EvalResult.Val.isInt() && !EvalResult.HasSideEffects;
+ bool Folded =
+ E->EvaluateAsRValue(EvalResult, Context, /*isConstantContext*/ true) &&
+ EvalResult.Val.isInt() && !EvalResult.HasSideEffects;
+
+ if (!isa<ConstantExpr>(E))
+ E = ConstantExpr::Create(Context, E, EvalResult.Val);
// In C++11, we can rely on diagnostics being produced for any expression
// which is not a constant expression. If no diagnostics were produced, then
@@ -14368,14 +14664,7 @@ namespace {
// Make sure we redo semantic analysis
bool AlwaysRebuild() { return true; }
-
- // Make sure we handle LabelStmts correctly.
- // FIXME: This does the right thing, but maybe we need a more general
- // fix to TreeTransform?
- StmtResult TransformLabelStmt(LabelStmt *S) {
- S->getDecl()->setStmt(nullptr);
- return BaseTransform::TransformLabelStmt(S);
- }
+ bool ReplacingOriginal() { return true; }
// We need to special-case DeclRefExprs referring to FieldDecls which
// are not part of a member pointer formation; normal TreeTransforming
@@ -14402,9 +14691,12 @@ namespace {
return BaseTransform::TransformUnaryOperator(E);
}
- ExprResult TransformLambdaExpr(LambdaExpr *E) {
- // Lambdas never need to be transformed.
- return E;
+ // The body of a lambda-expression is in a separate expression evaluation
+ // context so never needs to be transformed.
+ // FIXME: Ideally we wouldn't transform the closure type either, and would
+ // just recreate the capture expressions and lambda expression.
+ StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) {
+ return SkipLambdaBody(E, Body);
}
};
}
@@ -14512,13 +14804,6 @@ void Sema::PopExpressionEvaluationContext() {
for (const auto *L : Rec.Lambdas)
Diag(L->getBeginLoc(), D);
- } else {
- // Mark the capture expressions odr-used. This was deferred
- // during lambda expression creation.
- for (auto *Lambda : Rec.Lambdas) {
- for (auto *C : Lambda->capture_inits())
- MarkDeclarationsReferencedInExpr(C);
- }
}
}
@@ -14566,55 +14851,155 @@ ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
return TransformToPotentiallyEvaluated(E);
}
-/// Are we within a context in which some evaluation could be performed (be it
-/// constant evaluation or runtime evaluation)? Sadly, this notion is not quite
-/// captured by C++'s idea of an "unevaluated context".
-static bool isEvaluatableContext(Sema &SemaRef) {
+/// Are we in a context that is potentially constant evaluated per C++20
+/// [expr.const]p12?
+static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) {
+ /// C++2a [expr.const]p12:
+ // An expression or conversion is potentially constant evaluated if it is
switch (SemaRef.ExprEvalContexts.back().Context) {
- case Sema::ExpressionEvaluationContext::Unevaluated:
- case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
- // Expressions in this context are never evaluated.
- return false;
-
- case Sema::ExpressionEvaluationContext::UnevaluatedList:
case Sema::ExpressionEvaluationContext::ConstantEvaluated:
+ // -- a manifestly constant-evaluated expression,
case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
case Sema::ExpressionEvaluationContext::DiscardedStatement:
- // Expressions in this context could be evaluated.
+ // -- a potentially-evaluated expression,
+ case Sema::ExpressionEvaluationContext::UnevaluatedList:
+ // -- an immediate subexpression of a braced-init-list,
+
+ // -- [FIXME] an expression of the form & cast-expression that occurs
+ // within a templated entity
+ // -- a subexpression of one of the above that is not a subexpression of
+ // a nested unevaluated operand.
return true;
- case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
- // Referenced declarations will only be used if the construct in the
- // containing expression is used, at which point we'll be given another
- // turn to mark them.
+ case Sema::ExpressionEvaluationContext::Unevaluated:
+ case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
+ // Expressions in this context are never evaluated.
return false;
}
llvm_unreachable("Invalid context");
}
+/// Return true if this function has a calling convention that requires mangling
+/// in the size of the parameter pack.
+static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) {
+ // These manglings don't do anything on non-Windows or non-x86 platforms, so
+ // we don't need parameter type sizes.
+ const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
+ if (!TT.isOSWindows() || (TT.getArch() != llvm::Triple::x86 &&
+ TT.getArch() != llvm::Triple::x86_64))
+ return false;
+
+ // If this is C++ and this isn't an extern "C" function, parameters do not
+ // need to be complete. In this case, C++ mangling will apply, which doesn't
+ // use the size of the parameters.
+ if (S.getLangOpts().CPlusPlus && !FD->isExternC())
+ return false;
+
+ // Stdcall, fastcall, and vectorcall need this special treatment.
+ CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
+ switch (CC) {
+ case CC_X86StdCall:
+ case CC_X86FastCall:
+ case CC_X86VectorCall:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/// Require that all of the parameter types of function be complete. Normally,
+/// parameter types are only required to be complete when a function is called
+/// or defined, but to mangle functions with certain calling conventions, the
+/// mangler needs to know the size of the parameter list. In this situation,
+/// MSVC doesn't emit an error or instantiate templates. Instead, MSVC mangles
+/// the function as _foo@0, i.e. zero bytes of parameters, which will usually
+/// result in a linker error. Clang doesn't implement this behavior, and instead
+/// attempts to error at compile time.
+static void CheckCompleteParameterTypesForMangler(Sema &S, FunctionDecl *FD,
+ SourceLocation Loc) {
+ class ParamIncompleteTypeDiagnoser : public Sema::TypeDiagnoser {
+ FunctionDecl *FD;
+ ParmVarDecl *Param;
+
+ public:
+ ParamIncompleteTypeDiagnoser(FunctionDecl *FD, ParmVarDecl *Param)
+ : FD(FD), Param(Param) {}
+
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
+ CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
+ StringRef CCName;
+ switch (CC) {
+ case CC_X86StdCall:
+ CCName = "stdcall";
+ break;
+ case CC_X86FastCall:
+ CCName = "fastcall";
+ break;
+ case CC_X86VectorCall:
+ CCName = "vectorcall";
+ break;
+ default:
+ llvm_unreachable("CC does not need mangling");
+ }
+
+ S.Diag(Loc, diag::err_cconv_incomplete_param_type)
+ << Param->getDeclName() << FD->getDeclName() << CCName;
+ }
+ };
+
+ for (ParmVarDecl *Param : FD->parameters()) {
+ ParamIncompleteTypeDiagnoser Diagnoser(FD, Param);
+ S.RequireCompleteType(Loc, Param->getType(), Diagnoser);
+ }
+}
+
+namespace {
+enum class OdrUseContext {
+ /// Declarations in this context are not odr-used.
+ None,
+ /// Declarations in this context are formally odr-used, but this is a
+ /// dependent context.
+ Dependent,
+ /// Declarations in this context are odr-used but not actually used (yet).
+ FormallyOdrUsed,
+ /// Declarations in this context are used.
+ Used
+};
+}
+
/// Are we within a context in which references to resolved functions or to
/// variables result in odr-use?
-static bool isOdrUseContext(Sema &SemaRef, bool SkipDependentUses = true) {
- // An expression in a template is not really an expression until it's been
- // instantiated, so it doesn't trigger odr-use.
- if (SkipDependentUses && SemaRef.CurContext->isDependentContext())
- return false;
+static OdrUseContext isOdrUseContext(Sema &SemaRef) {
+ OdrUseContext Result;
switch (SemaRef.ExprEvalContexts.back().Context) {
case Sema::ExpressionEvaluationContext::Unevaluated:
case Sema::ExpressionEvaluationContext::UnevaluatedList:
case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
- case Sema::ExpressionEvaluationContext::DiscardedStatement:
- return false;
+ return OdrUseContext::None;
case Sema::ExpressionEvaluationContext::ConstantEvaluated:
case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
- return true;
+ Result = OdrUseContext::Used;
+ break;
+
+ case Sema::ExpressionEvaluationContext::DiscardedStatement:
+ Result = OdrUseContext::FormallyOdrUsed;
+ break;
case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
- return false;
+ // A default argument formally results in odr-use, but doesn't actually
+ // result in a use in any real sense until it itself is used.
+ Result = OdrUseContext::FormallyOdrUsed;
+ break;
}
- llvm_unreachable("Invalid context");
+
+ if (SemaRef.CurContext->isDependentContext())
+ return OdrUseContext::Dependent;
+
+ return Result;
}
static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
@@ -14631,6 +15016,10 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
Func->setReferenced();
+ // Recursive functions aren't really used until they're used from some other
+ // context.
+ bool IsRecursiveCall = CurContext == Func;
+
// C++11 [basic.def.odr]p3:
// A function whose name appears as a potentially-evaluated expression is
// odr-used if it is the unique lookup result or the selected member of a
@@ -14638,7 +15027,18 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
//
// We (incorrectly) mark overload resolution as an unevaluated context, so we
// can just check that here.
- bool OdrUse = MightBeOdrUse && isOdrUseContext(*this);
+ OdrUseContext OdrUse =
+ MightBeOdrUse ? isOdrUseContext(*this) : OdrUseContext::None;
+ if (IsRecursiveCall && OdrUse == OdrUseContext::Used)
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+
+ // C++20 [expr.const]p12:
+ // A function [...] is needed for constant evaluation if it is [...] a
+ // constexpr function that is named by an expression that is potentially
+ // constant evaluated
+ bool NeededForConstantEvaluation =
+ isPotentiallyConstantEvaluatedContext(*this) &&
+ isImplicitlyDefinableConstexprFunction(Func);
// Determine whether we require a function definition to exist, per
// C++11 [temp.inst]p3:
@@ -14646,12 +15046,23 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// 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.
+ // C++20 [temp.inst]p7:
+ // The existence of a definition of a [...] function is considered to
+ // affect the semantics of the program if the [...] function is needed for
+ // constant evaluation by an expression
+ // C++20 [basic.def.odr]p10:
+ // Every program shall contain exactly one definition of every non-inline
+ // function or variable that is odr-used in that program outside of a
+ // discarded statement
+ // C++20 [special]p1:
+ // The implementation will implicitly define [defaulted special members]
+ // if they are odr-used or needed for constant evaluation.
//
- // That is either when this is an odr-use, or when a usage of a constexpr
- // function occurs within an evaluatable context.
- bool NeedDefinition =
- OdrUse || (isEvaluatableContext(*this) &&
- isImplicitlyDefinableConstexprFunction(Func));
+ // Note that we skip the implicit instantiation of templates that are only
+ // used in unused default arguments or by recursive calls to themselves.
+ // This is formally non-conforming, but seems reasonable in practice.
+ bool NeedDefinition = !IsRecursiveCall && (OdrUse == OdrUseContext::Used ||
+ NeededForConstantEvaluation);
// C++14 [temp.expl.spec]p6:
// If a template [...] is explicitly specialized then that specialization
@@ -14676,123 +15087,168 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
ResolveExceptionSpec(Loc, FPT);
- // If we don't need to mark the function as used, and we don't need to
- // try to provide a definition, there's nothing more to do.
- if ((Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) &&
- (!NeedDefinition || Func->getBody()))
- return;
-
- // Note that this declaration has been used.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
- Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
- if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
- if (Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial() && !Constructor->hasAttr<DLLExportAttr>())
+ if (getLangOpts().CUDA)
+ CheckCUDACall(Loc, Func);
+
+ // If we need a definition, try to create one.
+ if (NeedDefinition && !Func->getBody()) {
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+ Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
+ if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
+ if (Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial() &&
+ !Constructor->hasAttr<DLLExportAttr>())
+ return;
+ DefineImplicitDefaultConstructor(Loc, Constructor);
+ } else if (Constructor->isCopyConstructor()) {
+ DefineImplicitCopyConstructor(Loc, Constructor);
+ } else if (Constructor->isMoveConstructor()) {
+ DefineImplicitMoveConstructor(Loc, Constructor);
+ }
+ } else if (Constructor->getInheritedConstructor()) {
+ DefineInheritingConstructor(Loc, Constructor);
+ }
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(Func)) {
+ Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+ if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
+ if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
- DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isCopyConstructor()) {
- DefineImplicitCopyConstructor(Loc, Constructor);
- } else if (Constructor->isMoveConstructor()) {
- DefineImplicitMoveConstructor(Loc, Constructor);
+ DefineImplicitDestructor(Loc, Destructor);
}
- } else if (Constructor->getInheritedConstructor()) {
- DefineInheritingConstructor(Loc, Constructor);
- }
- } else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(Func)) {
- Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
- if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
- if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
- return;
- DefineImplicitDestructor(Loc, Destructor);
- }
- if (Destructor->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, Destructor->getParent());
- } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
- if (MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal) {
- MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
- if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
- if (MethodDecl->isCopyAssignmentOperator())
- DefineImplicitCopyAssignment(Loc, MethodDecl);
- else if (MethodDecl->isMoveAssignmentOperator())
- DefineImplicitMoveAssignment(Loc, MethodDecl);
+ if (Destructor->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, Destructor->getParent());
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
+ if (MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
+ if (MethodDecl->isCopyAssignmentOperator())
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
+ else if (MethodDecl->isMoveAssignmentOperator())
+ DefineImplicitMoveAssignment(Loc, MethodDecl);
+ }
+ } else if (isa<CXXConversionDecl>(MethodDecl) &&
+ MethodDecl->getParent()->isLambda()) {
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
+ if (Conversion->isLambdaToBlockPointerConversion())
+ DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
+ else
+ DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
+ } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, MethodDecl->getParent());
+ }
+
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
+ if (Func->isImplicitlyInstantiable()) {
+ TemplateSpecializationKind TSK =
+ Func->getTemplateSpecializationKindForInstantiation();
+ SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
+ bool FirstInstantiation = PointOfInstantiation.isInvalid();
+ if (FirstInstantiation) {
+ PointOfInstantiation = Loc;
+ Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ } else if (TSK != TSK_ImplicitInstantiation) {
+ // Use the point of use as the point of instantiation, instead of the
+ // point of explicit instantiation (which we track as the actual point
+ // of instantiation). This gives better backtraces in diagnostics.
+ PointOfInstantiation = Loc;
}
- } else if (isa<CXXConversionDecl>(MethodDecl) &&
- MethodDecl->getParent()->isLambda()) {
- CXXConversionDecl *Conversion =
- cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
- if (Conversion->isLambdaToBlockPointerConversion())
- DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
- else
- DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
- } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, MethodDecl->getParent());
- }
-
- // Recursive functions should be marked when used from another function.
- // FIXME: Is this really right?
- if (CurContext == Func) return;
-
- // Implicit instantiation of function templates and member functions of
- // class templates.
- if (Func->isImplicitlyInstantiable()) {
- TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind();
- SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
- bool FirstInstantiation = PointOfInstantiation.isInvalid();
- if (FirstInstantiation) {
- PointOfInstantiation = Loc;
- Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- } else if (TSK != TSK_ImplicitInstantiation) {
- // Use the point of use as the point of instantiation, instead of the
- // point of explicit instantiation (which we track as the actual point of
- // instantiation). This gives better backtraces in diagnostics.
- PointOfInstantiation = Loc;
- }
-
- if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
- Func->isConstexpr()) {
- if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
- cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
- CodeSynthesisContexts.size())
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- else if (Func->isConstexpr())
- // Do not defer instantiations of constexpr functions, to avoid the
- // expression evaluator needing to call back into Sema if it sees a
- // call to such a function.
- InstantiateFunctionDefinition(PointOfInstantiation, Func);
- else {
- Func->setInstantiationIsPending(true);
- PendingInstantiations.push_back(std::make_pair(Func,
- PointOfInstantiation));
- // Notify the consumer that a function was implicitly instantiated.
- Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+
+ if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
+ Func->isConstexpr()) {
+ if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+ CodeSynthesisContexts.size())
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ else if (Func->isConstexpr())
+ // Do not defer instantiations of constexpr functions, to avoid the
+ // expression evaluator needing to call back into Sema if it sees a
+ // call to such a function.
+ InstantiateFunctionDefinition(PointOfInstantiation, Func);
+ else {
+ Func->setInstantiationIsPending(true);
+ PendingInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ // Notify the consumer that a function was implicitly instantiated.
+ Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ }
+ }
+ } else {
+ // Walk redefinitions, as some of them may be instantiable.
+ for (auto i : Func->redecls()) {
+ if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+ MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
- }
- } else {
- // Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
- if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, i, OdrUse);
}
}
- if (!OdrUse) return;
+ // If this is the first "real" use, act on that.
+ if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) {
+ // Keep track of used but undefined functions.
+ if (!Func->isDefined()) {
+ if (mightHaveNonExternalLinkage(Func))
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ else if (Func->getMostRecentDecl()->isInlined() &&
+ !LangOpts.GNUInline &&
+ !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>())
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ else if (isExternalWithNoLinkageType(Func))
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ }
+
+ // Some x86 Windows calling conventions mangle the size of the parameter
+ // pack into the name. Computing the size of the parameters requires the
+ // parameter types to be complete. Check that now.
+ if (funcHasParameterSizeMangling(*this, Func))
+ CheckCompleteParameterTypesForMangler(*this, Func, Loc);
- // Keep track of used but undefined functions.
- if (!Func->isDefined()) {
- if (mightHaveNonExternalLinkage(Func))
- UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
- else if (Func->getMostRecentDecl()->isInlined() &&
- !LangOpts.GNUInline &&
- !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>())
- UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
- else if (isExternalWithNoLinkageType(Func))
- UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ Func->markUsed(Context);
+
+ if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+ checkOpenMPDeviceFunction(Loc, Func);
}
+}
- Func->markUsed(Context);
+/// Directly mark a variable odr-used. Given a choice, prefer to use
+/// MarkVariableReferenced since it does additional checks and then
+/// calls MarkVarDeclODRUsed.
+/// If the variable must be captured:
+/// - if FunctionScopeIndexToStopAt is null, capture it in the CurContext
+/// - else capture it in the DeclContext that maps to the
+/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
+static void
+MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
+ const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
+ // Keep track of used but undefined variables.
+ // FIXME: We shouldn't suppress this warning for static data members.
+ if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
+ (!Var->isExternallyVisible() || Var->isInline() ||
+ SemaRef.isExternalWithNoLinkageType(Var)) &&
+ !(Var->isStaticDataMember() && Var->hasInit())) {
+ SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
+ if (old.isInvalid())
+ old = Loc;
+ }
+ QualType CaptureType, DeclRefType;
+ if (SemaRef.LangOpts.OpenMP)
+ SemaRef.tryCaptureOpenMPLambdas(Var);
+ SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true,
+ CaptureType, DeclRefType,
+ FunctionScopeIndexToStopAt);
+
+ Var->markUsed(SemaRef.Context);
+}
+
+void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
+ SourceLocation Loc,
+ unsigned CapturingScopeIndex) {
+ MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex);
}
static void
@@ -14958,31 +15414,35 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
QualType &CaptureType,
QualType &DeclRefType,
const bool Nested,
- Sema &S) {
- Expr *CopyExpr = nullptr;
+ Sema &S, bool Invalid) {
bool ByRef = false;
// Blocks are not allowed to capture arrays, excepting OpenCL.
// OpenCL v2.0 s1.12.5 (revision 40): arrays are captured by reference
// (decayed to pointers).
- if (!S.getLangOpts().OpenCL && CaptureType->isArrayType()) {
+ if (!Invalid && !S.getLangOpts().OpenCL && CaptureType->isArrayType()) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_ref_array_type);
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
+ Invalid = true;
+ } else {
+ return false;
}
- return false;
}
// Forbid the block-capture of autoreleasing variables.
- if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (!Invalid &&
+ CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_arc_autoreleasing_capture)
<< /*block*/ 0;
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
+ Invalid = true;
+ } else {
+ return false;
}
- return false;
}
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
@@ -15005,7 +15465,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
QualType PointeeTy = PT->getPointeeType();
- if (PointeeTy->getAs<ObjCObjectPointerType>() &&
+ if (!Invalid && PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
!IsObjCOwnershipAttributedType(PointeeTy)) {
if (BuildAndDiagnose) {
@@ -15026,54 +15486,14 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Block capture by copy introduces 'const'.
CaptureType = CaptureType.getNonReferenceType().withConst();
DeclRefType = CaptureType;
-
- if (S.getLangOpts().CPlusPlus && BuildAndDiagnose) {
- if (const RecordType *Record = DeclRefType->getAs<RecordType>()) {
- // The capture logic needs the destructor, so make sure we mark it.
- // Usually this is unnecessary because most local variables have
- // their destructors marked at declaration time, but parameters are
- // an exception because it's technically only the call site that
- // actually requires the destructor.
- if (isa<ParmVarDecl>(Var))
- S.FinalizeVarWithDestructor(Var, Record);
-
- // Enter a new evaluation context to insulate the copy
- // full-expression.
- EnterExpressionEvaluationContext scope(
- S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
-
- // According to the blocks spec, the capture of a variable from
- // the stack requires a const copy constructor. This is not true
- // of the copy/move done to move a __block variable to the heap.
- Expr *DeclRef = new (S.Context) DeclRefExpr(
- S.Context, Var, Nested, DeclRefType.withConst(), VK_LValue, Loc);
-
- ExprResult Result
- = S.PerformCopyInitialization(
- InitializedEntity::InitializeBlock(Var->getLocation(),
- CaptureType, false),
- Loc, DeclRef);
-
- // Build a full-expression copy expression if initialization
- // succeeded and used a non-trivial constructor. Recover from
- // errors by pretending that the copy isn't necessary.
- if (!Result.isInvalid() &&
- !cast<CXXConstructExpr>(Result.get())->getConstructor()
- ->isTrivial()) {
- Result = S.MaybeCreateExprWithCleanups(Result);
- CopyExpr = Result.get();
- }
- }
- }
}
// Actually capture the variable.
if (BuildAndDiagnose)
- BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
- SourceLocation(), CaptureType, CopyExpr);
-
- return true;
+ BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc, SourceLocation(),
+ CaptureType, Invalid);
+ return !Invalid;
}
@@ -15085,7 +15505,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
QualType &CaptureType,
QualType &DeclRefType,
const bool RefersToCapturedVariable,
- Sema &S) {
+ Sema &S, bool Invalid) {
// By default, capture variables by reference.
bool ByRef = true;
// Using an LValue reference type is consistent with Lambdas (see below).
@@ -15105,69 +15525,12 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
else
CaptureType = DeclRefType;
- Expr *CopyExpr = nullptr;
- if (BuildAndDiagnose) {
- // The current implementation assumes that all variables are captured
- // by references. Since there is no capture by copy, no expression
- // evaluation will be needed.
- RecordDecl *RD = RSI->TheRecordDecl;
-
- FieldDecl *Field
- = FieldDecl::Create(S.Context, RD, Loc, Loc, nullptr, CaptureType,
- S.Context.getTrivialTypeSourceInfo(CaptureType, Loc),
- nullptr, false, ICIS_NoInit);
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- RD->addDecl(Field);
- if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
- S.setOpenMPCaptureKind(Field, Var, RSI->OpenMPLevel);
-
- CopyExpr = new (S.Context) DeclRefExpr(
- S.Context, Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc);
- Var->setReferenced(true);
- Var->markUsed(S.Context);
- }
-
// Actually capture the variable.
if (BuildAndDiagnose)
- RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc,
- SourceLocation(), CaptureType, CopyExpr);
-
+ RSI->addCapture(Var, /*isBlock*/ false, ByRef, RefersToCapturedVariable,
+ Loc, SourceLocation(), CaptureType, Invalid);
- return true;
-}
-
-/// Create a field within the lambda class for the variable
-/// being captured.
-static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI,
- QualType FieldType, QualType DeclRefType,
- SourceLocation Loc,
- bool RefersToCapturedVariable) {
- CXXRecordDecl *Lambda = LSI->Lambda;
-
- // Build the non-static data member.
- FieldDecl *Field
- = FieldDecl::Create(S.Context, Lambda, Loc, Loc, nullptr, FieldType,
- S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
- nullptr, false, ICIS_NoInit);
- // If the variable being captured has an invalid type, mark the lambda class
- // as invalid as well.
- if (!FieldType->isDependentType()) {
- if (S.RequireCompleteType(Loc, FieldType, diag::err_field_incomplete)) {
- Lambda->setInvalidDecl();
- Field->setInvalidDecl();
- } else {
- NamedDecl *Def;
- FieldType->isIncompleteType(&Def);
- if (Def && Def->isInvalidDecl()) {
- Lambda->setInvalidDecl();
- Field->setInvalidDecl();
- }
- }
- }
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- Lambda->addDecl(Field);
+ return !Invalid;
}
/// Capture the given variable in the lambda.
@@ -15181,8 +15544,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
const Sema::TryCaptureKind Kind,
SourceLocation EllipsisLoc,
const bool IsTopScope,
- Sema &S) {
-
+ Sema &S, bool Invalid) {
// Determine whether we are capturing by reference or by value.
bool ByRef = false;
if (IsTopScope && Kind != Sema::TryCapture_Implicit) {
@@ -15223,34 +15585,31 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
}
// Forbid the lambda copy-capture of autoreleasing variables.
- if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (!Invalid &&
+ CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1;
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
+ Invalid = true;
+ } else {
+ return false;
}
- return false;
}
// Make sure that by-copy captures are of a complete and non-abstract type.
- if (BuildAndDiagnose) {
+ if (!Invalid && BuildAndDiagnose) {
if (!CaptureType->isDependentType() &&
S.RequireCompleteType(Loc, CaptureType,
diag::err_capture_of_incomplete_type,
Var->getDeclName()))
- return false;
-
- if (S.RequireNonAbstractType(Loc, CaptureType,
- diag::err_capture_of_abstract_type))
- return false;
+ Invalid = true;
+ else if (S.RequireNonAbstractType(Loc, CaptureType,
+ diag::err_capture_of_abstract_type))
+ Invalid = true;
}
}
- // Capture this variable in the lambda.
- if (BuildAndDiagnose)
- addAsFieldToClosureType(S, LSI, CaptureType, DeclRefType, Loc,
- RefersToCapturedVariable);
-
// Compute the type of a reference to this captured variable.
if (ByRef)
DeclRefType = CaptureType.getNonReferenceType();
@@ -15267,10 +15626,10 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
// Add the capture.
if (BuildAndDiagnose)
- LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
- Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr);
+ LSI->addCapture(Var, /*isBlock=*/false, ByRef, RefersToCapturedVariable,
+ Loc, EllipsisLoc, CaptureType, Invalid);
- return true;
+ return !Invalid;
}
bool Sema::tryCaptureVariable(
@@ -15304,7 +15663,9 @@ 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 && isOpenMPCapturedDecl(Var)))
+ if (IsGlobal &&
+ !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true,
+ MaxFunctionScopesIndex)))
return true;
Var = Var->getCanonicalDecl();
@@ -15366,11 +15727,6 @@ bool Sema::tryCaptureVariable(
}
return true;
}
- // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
- // certain types of variables (unnamed, variably modified types etc.)
- // so check for eligibility.
- if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this))
- return true;
// Try to capture variable-length arrays types.
if (Var->getType()->isVariablyModifiedType()) {
@@ -15441,33 +15797,45 @@ bool Sema::tryCaptureVariable(
// requirements, and adding captures if requested.
// If the variable had already been captured previously, we start capturing
// at the lambda nested within that one.
+ bool Invalid = false;
for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N;
++I) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
+ // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
+ // certain types of variables (unnamed, variably modified types etc.)
+ // so check for eligibility.
+ if (!Invalid)
+ Invalid =
+ !isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this);
+
+ // After encountering an error, if we're actually supposed to capture, keep
+ // capturing in nested contexts to suppress any follow-on diagnostics.
+ if (Invalid && !BuildAndDiagnose)
+ return true;
+
if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(CSI)) {
- if (!captureInBlock(BSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
- DeclRefType, Nested, *this))
- return true;
+ Invalid = !captureInBlock(BSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
+ DeclRefType, Nested, *this, Invalid);
Nested = true;
} else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- if (!captureInCapturedRegion(RSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
- DeclRefType, Nested, *this))
- return true;
+ Invalid = !captureInCapturedRegion(RSI, Var, ExprLoc, BuildAndDiagnose,
+ CaptureType, DeclRefType, Nested,
+ *this, Invalid);
Nested = true;
} else {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
- if (!captureInLambda(LSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
+ Invalid =
+ !captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
DeclRefType, Nested, Kind, EllipsisLoc,
- /*IsTopScope*/I == N - 1, *this))
- return true;
+ /*IsTopScope*/ I == N - 1, *this, Invalid);
Nested = true;
}
+
+ if (Invalid && !BuildAndDiagnose)
+ return true;
}
- return false;
+ return Invalid;
}
bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
@@ -15500,52 +15868,376 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
return DeclRefType;
}
-
-
-// If either the type of the variable or the initializer is dependent,
-// return false. Otherwise, determine whether the variable is a constant
-// expression. Use this if you need to know if a variable that might or
-// might not be dependent is truly a constant expression.
-static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
- ASTContext &Context) {
-
- if (Var->getType()->isDependentType())
- return false;
- const VarDecl *DefVD = nullptr;
- Var->getAnyInitializer(DefVD);
- if (!DefVD)
- return false;
- EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
- Expr *Init = cast<Expr>(Eval->Value);
- if (Init->isValueDependent())
- return false;
- return IsVariableAConstantExpression(Var, Context);
+namespace {
+// Helper to copy the template arguments from a DeclRefExpr or MemberExpr.
+// The produced TemplateArgumentListInfo* points to data stored within this
+// object, so should only be used in contexts where the pointer will not be
+// used after the CopiedTemplateArgs object is destroyed.
+class CopiedTemplateArgs {
+ bool HasArgs;
+ TemplateArgumentListInfo TemplateArgStorage;
+public:
+ template<typename RefExpr>
+ CopiedTemplateArgs(RefExpr *E) : HasArgs(E->hasExplicitTemplateArgs()) {
+ if (HasArgs)
+ E->copyTemplateArgumentsInto(TemplateArgStorage);
+ }
+ operator TemplateArgumentListInfo*()
+#ifdef __has_cpp_attribute
+#if __has_cpp_attribute(clang::lifetimebound)
+ [[clang::lifetimebound]]
+#endif
+#endif
+ {
+ return HasArgs ? &TemplateArgStorage : nullptr;
+ }
+};
}
-
-void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
+/// Walk the set of potential results of an expression and mark them all as
+/// non-odr-uses if they satisfy the side-conditions of the NonOdrUseReason.
+///
+/// \return A new expression if we found any potential results, ExprEmpty() if
+/// not, and ExprError() if we diagnosed an error.
+static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
+ NonOdrUseReason NOUR) {
// Per C++11 [basic.def.odr], a variable is odr-used "unless it is
// an object that satisfies the requirements for appearing in a
// constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
// is immediately applied." This function handles the lvalue-to-rvalue
// conversion part.
- MaybeODRUseExprs.erase(E->IgnoreParens());
+ //
+ // If we encounter a node that claims to be an odr-use but shouldn't be, we
+ // transform it into the relevant kind of non-odr-use node and rebuild the
+ // tree of nodes leading to it.
+ //
+ // This is a mini-TreeTransform that only transforms a restricted subset of
+ // nodes (and only certain operands of them).
- // If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
- // to a variable that is a constant expression, and if so, identify it as
- // a reference to a variable that does not involve an odr-use of that
- // variable.
- if (LambdaScopeInfo *LSI = getCurLambda()) {
- Expr *SansParensExpr = E->IgnoreParens();
- VarDecl *Var = nullptr;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
- Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
- else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
- Var = dyn_cast<VarDecl>(ME->getMemberDecl());
+ // Rebuild a subexpression.
+ auto Rebuild = [&](Expr *Sub) {
+ return rebuildPotentialResultsAsNonOdrUsed(S, Sub, NOUR);
+ };
+
+ // Check whether a potential result satisfies the requirements of NOUR.
+ auto IsPotentialResultOdrUsed = [&](NamedDecl *D) {
+ // Any entity other than a VarDecl is always odr-used whenever it's named
+ // in a potentially-evaluated expression.
+ auto *VD = dyn_cast<VarDecl>(D);
+ if (!VD)
+ return true;
+
+ // C++2a [basic.def.odr]p4:
+ // A variable x whose name appears as a potentially-evalauted expression
+ // e is odr-used by e unless
+ // -- x is a reference that is usable in constant expressions, or
+ // -- x is a variable of non-reference type that is usable in constant
+ // expressions and has no mutable subobjects, and e is an element of
+ // the set of potential results of an expression of
+ // non-volatile-qualified non-class type to which the lvalue-to-rvalue
+ // conversion is applied, or
+ // -- x is a variable of non-reference type, and e is an element of the
+ // set of potential results of a discarded-value expression to which
+ // the lvalue-to-rvalue conversion is not applied
+ //
+ // We check the first bullet and the "potentially-evaluated" condition in
+ // BuildDeclRefExpr. We check the type requirements in the second bullet
+ // in CheckLValueToRValueConversionOperand below.
+ switch (NOUR) {
+ case NOUR_None:
+ case NOUR_Unevaluated:
+ llvm_unreachable("unexpected non-odr-use-reason");
+
+ case NOUR_Constant:
+ // Constant references were handled when they were built.
+ if (VD->getType()->isReferenceType())
+ return true;
+ if (auto *RD = VD->getType()->getAsCXXRecordDecl())
+ if (RD->hasMutableFields())
+ return true;
+ if (!VD->isUsableInConstantExpressions(S.Context))
+ return true;
+ break;
+
+ case NOUR_Discarded:
+ if (VD->getType()->isReferenceType())
+ return true;
+ break;
+ }
+ return false;
+ };
+
+ // Mark that this expression does not constitute an odr-use.
+ auto MarkNotOdrUsed = [&] {
+ S.MaybeODRUseExprs.erase(E);
+ if (LambdaScopeInfo *LSI = S.getCurLambda())
+ LSI->markVariableExprAsNonODRUsed(E);
+ };
+
+ // C++2a [basic.def.odr]p2:
+ // The set of potential results of an expression e is defined as follows:
+ switch (E->getStmtClass()) {
+ // -- If e is an id-expression, ...
+ case Expr::DeclRefExprClass: {
+ auto *DRE = cast<DeclRefExpr>(E);
+ if (DRE->isNonOdrUse() || IsPotentialResultOdrUsed(DRE->getDecl()))
+ break;
+
+ // Rebuild as a non-odr-use DeclRefExpr.
+ MarkNotOdrUsed();
+ return DeclRefExpr::Create(
+ S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(),
+ DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(),
+ DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(),
+ DRE->getFoundDecl(), CopiedTemplateArgs(DRE), NOUR);
+ }
+
+ case Expr::FunctionParmPackExprClass: {
+ auto *FPPE = cast<FunctionParmPackExpr>(E);
+ // If any of the declarations in the pack is odr-used, then the expression
+ // as a whole constitutes an odr-use.
+ for (VarDecl *D : *FPPE)
+ if (IsPotentialResultOdrUsed(D))
+ return ExprEmpty();
+
+ // FIXME: Rebuild as a non-odr-use FunctionParmPackExpr? In practice,
+ // nothing cares about whether we marked this as an odr-use, but it might
+ // be useful for non-compiler tools.
+ MarkNotOdrUsed();
+ break;
+ }
+
+ // -- If e is a subscripting operation with an array operand...
+ case Expr::ArraySubscriptExprClass: {
+ auto *ASE = cast<ArraySubscriptExpr>(E);
+ Expr *OldBase = ASE->getBase()->IgnoreImplicit();
+ if (!OldBase->getType()->isArrayType())
+ break;
+ ExprResult Base = Rebuild(OldBase);
+ if (!Base.isUsable())
+ return Base;
+ Expr *LHS = ASE->getBase() == ASE->getLHS() ? Base.get() : ASE->getLHS();
+ Expr *RHS = ASE->getBase() == ASE->getRHS() ? Base.get() : ASE->getRHS();
+ SourceLocation LBracketLoc = ASE->getBeginLoc(); // FIXME: Not stored.
+ return S.ActOnArraySubscriptExpr(nullptr, LHS, LBracketLoc, RHS,
+ ASE->getRBracketLoc());
+ }
+
+ case Expr::MemberExprClass: {
+ auto *ME = cast<MemberExpr>(E);
+ // -- If e is a class member access expression [...] naming a non-static
+ // data member...
+ if (isa<FieldDecl>(ME->getMemberDecl())) {
+ ExprResult Base = Rebuild(ME->getBase());
+ if (!Base.isUsable())
+ return Base;
+ return MemberExpr::Create(
+ S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(),
+ ME->getQualifierLoc(), ME->getTemplateKeywordLoc(),
+ ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(),
+ CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(),
+ ME->getObjectKind(), ME->isNonOdrUse());
+ }
+
+ if (ME->getMemberDecl()->isCXXInstanceMember())
+ break;
+
+ // -- If e is a class member access expression naming a static data member,
+ // ...
+ if (ME->isNonOdrUse() || IsPotentialResultOdrUsed(ME->getMemberDecl()))
+ break;
+
+ // Rebuild as a non-odr-use MemberExpr.
+ MarkNotOdrUsed();
+ return MemberExpr::Create(
+ S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
+ ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(),
+ ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME),
+ ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR);
+ return ExprEmpty();
+ }
+
+ case Expr::BinaryOperatorClass: {
+ auto *BO = cast<BinaryOperator>(E);
+ Expr *LHS = BO->getLHS();
+ Expr *RHS = BO->getRHS();
+ // -- If e is a pointer-to-member expression of the form e1 .* e2 ...
+ if (BO->getOpcode() == BO_PtrMemD) {
+ ExprResult Sub = Rebuild(LHS);
+ if (!Sub.isUsable())
+ return Sub;
+ LHS = Sub.get();
+ // -- If e is a comma expression, ...
+ } else if (BO->getOpcode() == BO_Comma) {
+ ExprResult Sub = Rebuild(RHS);
+ if (!Sub.isUsable())
+ return Sub;
+ RHS = Sub.get();
+ } else {
+ break;
+ }
+ return S.BuildBinOp(nullptr, BO->getOperatorLoc(), BO->getOpcode(),
+ LHS, RHS);
+ }
+
+ // -- If e has the form (e1)...
+ case Expr::ParenExprClass: {
+ auto *PE = cast<ParenExpr>(E);
+ ExprResult Sub = Rebuild(PE->getSubExpr());
+ if (!Sub.isUsable())
+ return Sub;
+ return S.ActOnParenExpr(PE->getLParen(), PE->getRParen(), Sub.get());
+ }
+
+ // -- If e is a glvalue conditional expression, ...
+ // We don't apply this to a binary conditional operator. FIXME: Should we?
+ case Expr::ConditionalOperatorClass: {
+ auto *CO = cast<ConditionalOperator>(E);
+ ExprResult LHS = Rebuild(CO->getLHS());
+ if (LHS.isInvalid())
+ return ExprError();
+ ExprResult RHS = Rebuild(CO->getRHS());
+ if (RHS.isInvalid())
+ return ExprError();
+ if (!LHS.isUsable() && !RHS.isUsable())
+ return ExprEmpty();
+ if (!LHS.isUsable())
+ LHS = CO->getLHS();
+ if (!RHS.isUsable())
+ RHS = CO->getRHS();
+ return S.ActOnConditionalOp(CO->getQuestionLoc(), CO->getColonLoc(),
+ CO->getCond(), LHS.get(), RHS.get());
+ }
+
+ // [Clang extension]
+ // -- If e has the form __extension__ e1...
+ case Expr::UnaryOperatorClass: {
+ auto *UO = cast<UnaryOperator>(E);
+ if (UO->getOpcode() != UO_Extension)
+ break;
+ ExprResult Sub = Rebuild(UO->getSubExpr());
+ if (!Sub.isUsable())
+ return Sub;
+ return S.BuildUnaryOp(nullptr, UO->getOperatorLoc(), UO_Extension,
+ Sub.get());
+ }
+
+ // [Clang extension]
+ // -- If e has the form _Generic(...), the set of potential results is the
+ // union of the sets of potential results of the associated expressions.
+ case Expr::GenericSelectionExprClass: {
+ auto *GSE = cast<GenericSelectionExpr>(E);
+
+ SmallVector<Expr *, 4> AssocExprs;
+ bool AnyChanged = false;
+ for (Expr *OrigAssocExpr : GSE->getAssocExprs()) {
+ ExprResult AssocExpr = Rebuild(OrigAssocExpr);
+ if (AssocExpr.isInvalid())
+ return ExprError();
+ if (AssocExpr.isUsable()) {
+ AssocExprs.push_back(AssocExpr.get());
+ AnyChanged = true;
+ } else {
+ AssocExprs.push_back(OrigAssocExpr);
+ }
+ }
- if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))
- LSI->markVariableExprAsNonODRUsed(SansParensExpr);
+ return AnyChanged ? S.CreateGenericSelectionExpr(
+ GSE->getGenericLoc(), GSE->getDefaultLoc(),
+ GSE->getRParenLoc(), GSE->getControllingExpr(),
+ GSE->getAssocTypeSourceInfos(), AssocExprs)
+ : ExprEmpty();
}
+
+ // [Clang extension]
+ // -- If e has the form __builtin_choose_expr(...), the set of potential
+ // results is the union of the sets of potential results of the
+ // second and third subexpressions.
+ case Expr::ChooseExprClass: {
+ auto *CE = cast<ChooseExpr>(E);
+
+ ExprResult LHS = Rebuild(CE->getLHS());
+ if (LHS.isInvalid())
+ return ExprError();
+
+ ExprResult RHS = Rebuild(CE->getLHS());
+ if (RHS.isInvalid())
+ return ExprError();
+
+ if (!LHS.get() && !RHS.get())
+ return ExprEmpty();
+ if (!LHS.isUsable())
+ LHS = CE->getLHS();
+ if (!RHS.isUsable())
+ RHS = CE->getRHS();
+
+ return S.ActOnChooseExpr(CE->getBuiltinLoc(), CE->getCond(), LHS.get(),
+ RHS.get(), CE->getRParenLoc());
+ }
+
+ // Step through non-syntactic nodes.
+ case Expr::ConstantExprClass: {
+ auto *CE = cast<ConstantExpr>(E);
+ ExprResult Sub = Rebuild(CE->getSubExpr());
+ if (!Sub.isUsable())
+ return Sub;
+ return ConstantExpr::Create(S.Context, Sub.get());
+ }
+
+ // We could mostly rely on the recursive rebuilding to rebuild implicit
+ // casts, but not at the top level, so rebuild them here.
+ case Expr::ImplicitCastExprClass: {
+ auto *ICE = cast<ImplicitCastExpr>(E);
+ // Only step through the narrow set of cast kinds we expect to encounter.
+ // Anything else suggests we've left the region in which potential results
+ // can be found.
+ switch (ICE->getCastKind()) {
+ case CK_NoOp:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ ExprResult Sub = Rebuild(ICE->getSubExpr());
+ if (!Sub.isUsable())
+ return Sub;
+ CXXCastPath Path(ICE->path());
+ return S.ImpCastExprToType(Sub.get(), ICE->getType(), ICE->getCastKind(),
+ ICE->getValueKind(), &Path);
+ }
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Can't traverse through this node. Nothing to do.
+ return ExprEmpty();
+}
+
+ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) {
+ // Check whether the operand is or contains an object of non-trivial C union
+ // type.
+ if (E->getType().isVolatileQualified() &&
+ (E->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
+ E->getType().hasNonTrivialToPrimitiveCopyCUnion()))
+ checkNonTrivialCUnion(E->getType(), E->getExprLoc(),
+ Sema::NTCUC_LValueToRValueVolatile,
+ NTCUK_Destruct|NTCUK_Copy);
+
+ // C++2a [basic.def.odr]p4:
+ // [...] an expression of non-volatile-qualified non-class type to which
+ // the lvalue-to-rvalue conversion is applied [...]
+ if (E->getType().isVolatileQualified() || E->getType()->getAs<RecordType>())
+ return E;
+
+ ExprResult Result =
+ rebuildPotentialResultsAsNonOdrUsed(*this, E, NOUR_Constant);
+ if (Result.isInvalid())
+ return ExprError();
+ return Result.get() ? Result : E;
}
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
@@ -15558,45 +16250,62 @@ ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
// deciding whether it is an odr-use, just assume we will apply the
// lvalue-to-rvalue conversion. In the one case where this doesn't happen
// (a non-type template argument), we have special handling anyway.
- UpdateMarkingForLValueToRValue(Res.get());
- return Res;
+ return CheckLValueToRValueConversionOperand(Res.get());
}
void Sema::CleanupVarDeclMarking() {
- for (Expr *E : MaybeODRUseExprs) {
- VarDecl *Var;
- SourceLocation Loc;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- Var = cast<VarDecl>(DRE->getDecl());
- Loc = DRE->getLocation();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- Var = cast<VarDecl>(ME->getMemberDecl());
- Loc = ME->getMemberLoc();
+ // Iterate through a local copy in case MarkVarDeclODRUsed makes a recursive
+ // call.
+ MaybeODRUseExprSet LocalMaybeODRUseExprs;
+ std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs);
+
+ for (Expr *E : LocalMaybeODRUseExprs) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ MarkVarDeclODRUsed(cast<VarDecl>(DRE->getDecl()),
+ DRE->getLocation(), *this);
+ } else if (auto *ME = dyn_cast<MemberExpr>(E)) {
+ MarkVarDeclODRUsed(cast<VarDecl>(ME->getMemberDecl()), ME->getMemberLoc(),
+ *this);
+ } else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
+ for (VarDecl *VD : *FP)
+ MarkVarDeclODRUsed(VD, FP->getParameterPackLocation(), *this);
} else {
llvm_unreachable("Unexpected expression");
}
-
- MarkVarDeclODRUsed(Var, Loc, *this,
- /*MaxFunctionScopeIndex Pointer*/ nullptr);
}
- MaybeODRUseExprs.clear();
+ assert(MaybeODRUseExprs.empty() &&
+ "MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?");
}
-
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
VarDecl *Var, Expr *E) {
- assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) &&
+ assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E) ||
+ isa<FunctionParmPackExpr>(E)) &&
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ if (Var->isInvalidDecl())
+ return;
+
+ auto *MSI = Var->getMemberSpecializationInfo();
+ TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind()
+ : Var->getTemplateSpecializationKind();
- bool OdrUseContext = isOdrUseContext(SemaRef);
+ OdrUseContext OdrUse = isOdrUseContext(SemaRef);
bool UsableInConstantExpr =
- Var->isUsableInConstantExpressions(SemaRef.Context);
+ Var->mightBeUsableInConstantExpressions(SemaRef.Context);
+
+ // C++20 [expr.const]p12:
+ // A variable [...] is needed for constant evaluation if it is [...] a
+ // variable whose name appears as a potentially constant evaluated
+ // expression that is either a contexpr variable or is of non-volatile
+ // const-qualified integral type or of reference type
+ bool NeededForConstantEvaluation =
+ isPotentiallyConstantEvaluatedContext(SemaRef) && UsableInConstantExpr;
+
bool NeedDefinition =
- OdrUseContext || (isEvaluatableContext(SemaRef) && UsableInConstantExpr);
+ OdrUse == OdrUseContext::Used || NeededForConstantEvaluation;
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -15623,11 +16332,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
(TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
if (TryInstantiating) {
- SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
+ SourceLocation PointOfInstantiation =
+ MSI ? MSI->getPointOfInstantiation() : Var->getPointOfInstantiation();
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
PointOfInstantiation = Loc;
- Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ if (MSI)
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ else
+ Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
bool InstantiationDependent = false;
@@ -15656,25 +16369,53 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
- // 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
- // it is an object, the lvalue-to-rvalue conversion (4.1)
- // is immediately applied." We check the first part here, and
- // Sema::UpdateMarkingForLValueToRValue deals with the second part.
- // Note that we use the C++11 definition everywhere because nothing in
- // C++03 depends on whether we get the C++03 version correct. The second
- // part does not apply to references, since they are not objects.
- if (OdrUseContext && E &&
- IsVariableAConstantExpression(Var, SemaRef.Context)) {
- // A reference initialized by a constant expression can never be
- // odr-used, so simply ignore it.
- if (!Var->getType()->isReferenceType() ||
- (SemaRef.LangOpts.OpenMP && SemaRef.isOpenMPCapturedDecl(Var)))
+ // C++2a [basic.def.odr]p4:
+ // A variable x whose name appears as a potentially-evaluated expression e
+ // is odr-used by e unless
+ // -- x is a reference that is usable in constant expressions
+ // -- x is a variable of non-reference type that is usable in constant
+ // expressions and has no mutable subobjects [FIXME], and e is an
+ // element of the set of potential results of an expression of
+ // non-volatile-qualified non-class type to which the lvalue-to-rvalue
+ // conversion is applied
+ // -- x is a variable of non-reference type, and e is an element of the set
+ // of potential results of a discarded-value expression to which the
+ // lvalue-to-rvalue conversion is not applied [FIXME]
+ //
+ // We check the first part of the second bullet here, and
+ // Sema::CheckLValueToRValueConversionOperand deals with the second part.
+ // FIXME: To get the third bullet right, we need to delay this even for
+ // variables that are not usable in constant expressions.
+
+ // If we already know this isn't an odr-use, there's nothing more to do.
+ if (DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
+ if (DRE->isNonOdrUse())
+ return;
+ if (MemberExpr *ME = dyn_cast_or_null<MemberExpr>(E))
+ if (ME->isNonOdrUse())
+ return;
+
+ switch (OdrUse) {
+ case OdrUseContext::None:
+ assert((!E || isa<FunctionParmPackExpr>(E)) &&
+ "missing non-odr-use marking for unevaluated decl ref");
+ break;
+
+ case OdrUseContext::FormallyOdrUsed:
+ // FIXME: Ignoring formal odr-uses results in incorrect lambda capture
+ // behavior.
+ break;
+
+ case OdrUseContext::Used:
+ // If we might later find that this expression isn't actually an odr-use,
+ // delay the marking.
+ if (E && Var->isUsableInConstantExpressions(SemaRef.Context))
SemaRef.MaybeODRUseExprs.insert(E);
- } else if (OdrUseContext) {
- MarkVarDeclODRUsed(Var, Loc, SemaRef,
- /*MaxFunctionScopeIndex ptr*/ nullptr);
- } else if (isOdrUseContext(SemaRef, /*SkipDependentUses*/false)) {
+ else
+ MarkVarDeclODRUsed(Var, Loc, SemaRef);
+ break;
+
+ case OdrUseContext::Dependent:
// If this is a dependent context, we don't need to mark variables as
// odr-used, but we may still need to track them for lambda capture.
// FIXME: Do we also need to do this inside dependent typeid expressions
@@ -15695,12 +16436,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// later (ActOnFinishFullExpr) for eventual capture and odr-use marking
// unless the variable is a reference that was initialized by a constant
// expression (this will never need to be captured or odr-used).
+ //
+ // FIXME: We can simplify this a lot after implementing P0588R1.
assert(E && "Capture variable should be used in an expression.");
if (!Var->getType()->isReferenceType() ||
- !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
+ !Var->isUsableInConstantExpressions(SemaRef.Context))
LSI->addPotentialCapture(E->IgnoreParens());
}
}
+ break;
}
}
@@ -15777,6 +16521,12 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse);
}
+/// Perform reference-marking and odr-use handling for a FunctionParmPackExpr.
+void Sema::MarkFunctionParmPackReferenced(FunctionParmPackExpr *E) {
+ for (VarDecl *VD : *E)
+ MarkExprReferenced(*this, E->getParameterPackLocation(), VD, E, true);
+}
+
/// 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
@@ -15903,13 +16653,6 @@ namespace {
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Visit(E->getExpr());
}
-
- void VisitImplicitCastExpr(ImplicitCastExpr *E) {
- Inherited::VisitImplicitCastExpr(E);
-
- if (E->getCastKind() == CK_LValueToRValue)
- S.UpdateMarkingForLValueToRValue(E->getSubExpr());
- }
};
}
@@ -15939,7 +16682,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
/// behavior of a program, such as passing a non-POD value through an ellipsis.
/// Failure to do so will likely result in spurious diagnostics or failures
/// during overload resolution or within sizeof/alignof/typeof/typeid.
-bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
+bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts,
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context) {
case ExpressionEvaluationContext::Unevaluated:
@@ -15955,9 +16698,9 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
case ExpressionEvaluationContext::PotentiallyEvaluated:
case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
- if (Statement && getCurFunctionOrMethodDecl()) {
+ if (!Stmts.empty() && getCurFunctionOrMethodDecl()) {
FunctionScopes.back()->PossiblyUnreachableDiags.
- push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement));
+ push_back(sema::PossiblyUnreachableDiag(PD, Loc, Stmts));
return true;
}
@@ -15982,6 +16725,12 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
return false;
}
+bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
+ const PartialDiagnostic &PD) {
+ return DiagRuntimeBehavior(
+ Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD);
+}
+
bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
CallExpr *CE, FunctionDecl *FD) {
if (ReturnType->isVoidType() || !ReturnType->isIncompleteType())
@@ -16548,13 +17297,11 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (DRE && Proto && Proto->getParamTypes().empty() && Proto->isVariadic()) {
SourceLocation Loc = FD->getLocation();
- FunctionDecl *NewFD = FunctionDecl::Create(S.Context,
- FD->getDeclContext(),
- Loc, Loc, FD->getNameInfo().getName(),
- DestType, FD->getTypeSourceInfo(),
- SC_None, false/*isInlineSpecified*/,
- FD->hasPrototype(),
- false/*isConstexprSpecified*/);
+ FunctionDecl *NewFD = FunctionDecl::Create(
+ S.Context, FD->getDeclContext(), Loc, Loc,
+ FD->getNameInfo().getName(), DestType, FD->getTypeSourceInfo(),
+ SC_None, false /*isInlineSpecified*/, FD->hasPrototype(),
+ /*ConstexprKind*/ CSK_unspecified);
if (FD->getQualifier())
NewFD->setQualifierInfo(FD->getQualifierLoc());
@@ -16843,10 +17590,9 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
StringRef Platform = getASTContext().getTargetInfo().getPlatformName();
- auto Spec = std::find_if(AvailSpecs.begin(), AvailSpecs.end(),
- [&](const AvailabilitySpec &Spec) {
- return Spec.getPlatform() == Platform;
- });
+ auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) {
+ return Spec.getPlatform() == Platform;
+ });
VersionTuple Version;
if (Spec != AvailSpecs.end())
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 8c89a3cee3db..705e3b9bd7fb 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1,9 +1,8 @@
//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -91,7 +90,7 @@ ParsedType Sema::getConstructorName(IdentifierInfo &II,
// When naming a constructor as a member of a dependent context (eg, in a
// friend declaration or an inherited constructor declaration), form an
// unresolved "typename" type.
- if (CurClass->isDependentContext() && !EnteringContext) {
+ if (CurClass->isDependentContext() && !EnteringContext && SS.getScopeRep()) {
QualType T = Context.getDependentNameType(ETK_None, SS.getScopeRep(), &II);
return ParsedType::make(T);
}
@@ -530,7 +529,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
ExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
- // OpenCL C++ 1.0 s2.9: typeid is not supported.
+ // typeid is not supported in OpenCL.
if (getLangOpts().OpenCLCPlusPlus) {
return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported)
<< "typeid");
@@ -751,12 +750,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
bool IsThrownVarInScope) {
// Don't report an error if 'throw' is used in system headers.
if (!getLangOpts().CXXExceptions &&
- !getSourceManager().isInSystemHeader(OpLoc) &&
- (!getLangOpts().OpenMPIsDevice ||
- !getLangOpts().OpenMPHostCXXExceptions ||
- isInOpenMPTargetExecutionDirective() ||
- isInOpenMPDeclareTargetContext()))
- Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
+ !getSourceManager().isInSystemHeader(OpLoc) && !getLangOpts().CUDA) {
+ // Delay error emission for the OpenMP device code.
+ targetDiag(OpLoc, diag::err_exceptions_disabled) << "throw";
+ }
// Exceptions aren't allowed in CUDA device code.
if (getLangOpts().CUDA)
@@ -944,6 +941,21 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
}
}
+ // Under the Itanium C++ ABI, memory for the exception object is allocated by
+ // the runtime with no ability for the compiler to request additional
+ // alignment. Warn if the exception type requires alignment beyond the minimum
+ // guaranteed by the target C++ runtime.
+ if (Context.getTargetInfo().getCXXABI().isItaniumFamily()) {
+ CharUnits TypeAlign = Context.getTypeAlignInChars(Ty);
+ CharUnits ExnObjAlign = Context.getExnObjectAlignment();
+ if (ExnObjAlign < TypeAlign) {
+ Diag(ThrowLoc, diag::warn_throw_underaligned_obj);
+ Diag(ThrowLoc, diag::note_throw_underaligned_obj)
+ << Ty << (unsigned)TypeAlign.getQuantity()
+ << (unsigned)ExnObjAlign.getQuantity();
+ }
+ }
+
return false;
}
@@ -1122,48 +1134,6 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() {
}
}
-static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD,
- QualType ThisTy, SourceLocation Loc,
- const bool ByCopy) {
-
- QualType AdjustedThisTy = ThisTy;
- // The type of the corresponding data member (not a 'this' pointer if 'by
- // copy').
- 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);
- 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, const bool Explicit,
bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt,
const bool ByCopy) {
@@ -1253,29 +1223,25 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
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.
QualType ThisTy = getCurrentThisType();
for (int idx = MaxFunctionScopesIndex; NumCapturingClosures;
--idx, --NumCapturingClosures) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
- Expr *ThisExpr = nullptr;
-
- if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
- // For lambda expressions, build a field and an initializing expression,
- // and capture the *enclosing object* by copy only if this is the first
- // iteration.
- ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc,
- ByCopy && idx == MaxFunctionScopesIndex);
- } else if (CapturedRegionScopeInfo *RSI
- = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx]))
- ThisExpr =
- captureThis(*this, Context, RSI->TheRecordDecl, ThisTy, Loc,
- false/*ByCopy*/);
+ // The type of the corresponding data member (not a 'this' pointer if 'by
+ // copy').
+ QualType CaptureType = 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'.
+ CaptureType = ThisTy->getPointeeType();
+ CaptureType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
+ }
bool isNested = NumCapturingClosures > 1;
- CSI->addThisCapture(isNested, Loc, ThisExpr, ByCopy);
+ CSI->addThisCapture(isNested, Loc, CaptureType, ByCopy);
}
return false;
}
@@ -1286,10 +1252,20 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// which the function is called.
QualType ThisTy = getCurrentThisType();
- if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
+ if (ThisTy.isNull())
+ return Diag(Loc, diag::err_invalid_this_use);
+ return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
+}
+
+Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
+ bool IsImplicit) {
+ auto *This = new (Context) CXXThisExpr(Loc, Type, IsImplicit);
+ MarkThisReferenced(This);
+ return This;
+}
- CheckCXXThisCapture(Loc);
- return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false);
+void Sema::MarkThisReferenced(CXXThisExpr *This) {
+ CheckCXXThisCapture(This->getExprLoc());
}
bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) {
@@ -1666,7 +1642,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
Declarator &D, Expr *Initializer) {
- Expr *ArraySize = nullptr;
+ Optional<Expr *> ArraySize;
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
@@ -1677,7 +1653,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (Chunk.Arr.hasStatic)
return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new)
<< D.getSourceRange());
- if (!Chunk.Arr.NumElts)
+ if (!Chunk.Arr.NumElts && !Initializer)
return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size)
<< D.getSourceRange());
@@ -1790,7 +1766,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceRange TypeIdParens,
QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
- Expr *ArraySize,
+ Optional<Expr *> ArraySize,
SourceRange DirectInitRange,
Expr *Initializer) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
@@ -1841,9 +1817,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
auto *Deduced = AllocType->getContainedDeducedType();
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
if (ArraySize)
- return ExprError(Diag(ArraySize->getExprLoc(),
- diag::err_deduced_class_template_compound_type)
- << /*array*/ 2 << ArraySize->getSourceRange());
+ return ExprError(
+ Diag(ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(),
+ diag::err_deduced_class_template_compound_type)
+ << /*array*/ 2
+ << (ArraySize ? (*ArraySize)->getSourceRange() : TypeRange));
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, AllocType);
@@ -1873,11 +1851,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (Braced && !getLangOpts().CPlusPlus17)
Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init)
<< AllocType << TypeRange;
+ Expr *Deduce = Inits[0];
QualType DeducedType;
- if (DeduceAutoType(AllocTypeInfo, Inits[0], DeducedType) == DAR_Failed)
+ if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
- << AllocType << Inits[0]->getType()
- << TypeRange << Inits[0]->getSourceRange());
+ << AllocType << Deduce->getType()
+ << TypeRange << Deduce->getSourceRange());
if (DeducedType.isNull())
return ExprError();
AllocType = DeducedType;
@@ -1908,8 +1887,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
QualType ResultType = Context.getPointerType(AllocType);
- if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(ArraySize);
+ if (ArraySize && *ArraySize &&
+ (*ArraySize)->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(*ArraySize);
if (result.isInvalid()) return ExprError();
ArraySize = result.get();
}
@@ -1921,19 +1901,19 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// C++1y [expr.new]p6: The expression [...] is implicitly converted to
// std::size_t.
llvm::Optional<uint64_t> KnownArraySize;
- if (ArraySize && !ArraySize->isTypeDependent()) {
+ if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) {
ExprResult ConvertedSize;
if (getLangOpts().CPlusPlus14) {
assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?");
- ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(),
+ ConvertedSize = PerformImplicitConversion(*ArraySize, Context.getSizeType(),
AA_Converting);
if (!ConvertedSize.isInvalid() &&
- ArraySize->getType()->getAs<RecordType>())
+ (*ArraySize)->getType()->getAs<RecordType>())
// Diagnose the compatibility of this conversion.
Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
- << ArraySize->getType() << 0 << "'size_t'";
+ << (*ArraySize)->getType() << 0 << "'size_t'";
} else {
class SizeConvertDiagnoser : public ICEConvertDiagnoser {
protected:
@@ -1987,16 +1967,16 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
: diag::ext_array_size_conversion)
<< T << ConvTy->isEnumeralType() << ConvTy;
}
- } SizeDiagnoser(ArraySize);
+ } SizeDiagnoser(*ArraySize);
- ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize,
+ ConvertedSize = PerformContextualImplicitConversion(StartLoc, *ArraySize,
SizeDiagnoser);
}
if (ConvertedSize.isInvalid())
return ExprError();
ArraySize = ConvertedSize.get();
- QualType SizeType = ArraySize->getType();
+ QualType SizeType = (*ArraySize)->getType();
if (!SizeType->isIntegralOrUnscopedEnumerationType())
return ExprError();
@@ -2008,18 +1988,18 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// Let's see if this is a constant < 0. If so, we reject it out of hand,
// per CWG1464. Otherwise, if it's not a constant, we must have an
// unparenthesized array type.
- if (!ArraySize->isValueDependent()) {
+ if (!(*ArraySize)->isValueDependent()) {
llvm::APSInt Value;
// We've already performed any required implicit conversion to integer or
// unscoped enumeration type.
// FIXME: Per CWG1464, we are required to check the value prior to
// converting to size_t. This will never find a negative array size in
// C++14 onwards, because Value is always unsigned here!
- if (ArraySize->isIntegerConstantExpr(Value, Context)) {
+ if ((*ArraySize)->isIntegerConstantExpr(Value, Context)) {
if (Value.isSigned() && Value.isNegative()) {
- return ExprError(Diag(ArraySize->getBeginLoc(),
+ return ExprError(Diag((*ArraySize)->getBeginLoc(),
diag::err_typecheck_negative_array_size)
- << ArraySize->getSourceRange());
+ << (*ArraySize)->getSourceRange());
}
if (!AllocType->isDependentType()) {
@@ -2027,15 +2007,15 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
return ExprError(
- Diag(ArraySize->getBeginLoc(), diag::err_array_too_large)
- << Value.toString(10) << ArraySize->getSourceRange());
+ Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large)
+ << Value.toString(10) << (*ArraySize)->getSourceRange());
}
KnownArraySize = Value.getZExtValue();
} else if (TypeIdParens.isValid()) {
// Can't have dynamic array size when the type-id is in parentheses.
- Diag(ArraySize->getBeginLoc(), diag::ext_new_paren_array_nonconst)
- << ArraySize->getSourceRange()
+ Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst)
+ << (*ArraySize)->getSourceRange()
<< FixItHint::CreateRemoval(TypeIdParens.getBegin())
<< FixItHint::CreateRemoval(TypeIdParens.getEnd());
@@ -2058,10 +2038,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both;
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
- FindAllocationFunctions(StartLoc,
- SourceRange(PlacementLParen, PlacementRParen),
- Scope, Scope, AllocType, ArraySize, PassAlignment,
- PlacementArgs, OperatorNew, OperatorDelete))
+ FindAllocationFunctions(
+ StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope,
+ AllocType, ArraySize.hasValue(), PassAlignment, PlacementArgs,
+ OperatorNew, OperatorDelete))
return ExprError();
// If this is an array allocation, compute whether the usual array
@@ -2154,6 +2134,22 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
FullInit = Binder->getSubExpr();
Initializer = FullInit.get();
+
+ // FIXME: If we have a KnownArraySize, check that the array bound of the
+ // initializer is no greater than that constant value.
+
+ if (ArraySize && !*ArraySize) {
+ auto *CAT = Context.getAsConstantArrayType(Initializer->getType());
+ if (CAT) {
+ // FIXME: Track that the array size was inferred rather than explicitly
+ // specified.
+ ArraySize = IntegerLiteral::Create(
+ Context, CAT->getSize(), Context.getSizeType(), TypeRange.getEnd());
+ } else {
+ Diag(TypeRange.getEnd(), diag::err_new_array_size_unknown_from_init)
+ << Initializer->getSourceRange();
+ }
+ }
}
// Mark the new and delete operators as referenced.
@@ -2168,24 +2164,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
MarkFunctionReferenced(StartLoc, OperatorDelete);
}
- // C++0x [expr.new]p17:
- // If the new expression creates an array of objects of class type,
- // access and ambiguity control are done for the destructor.
- QualType BaseAllocType = Context.getBaseElementType(AllocType);
- if (ArraySize && !BaseAllocType->isDependentType()) {
- if (const RecordType *BaseRecordType = BaseAllocType->getAs<RecordType>()) {
- if (CXXDestructorDecl *dtor = LookupDestructor(
- cast<CXXRecordDecl>(BaseRecordType->getDecl()))) {
- MarkFunctionReferenced(StartLoc, dtor);
- CheckDestructorAccess(StartLoc, dtor,
- PDiag(diag::err_access_dtor)
- << BaseAllocType);
- if (DiagnoseUseOfDecl(dtor, StartLoc))
- return ExprError();
- }
- }
- }
-
return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
PassAlignment, UsualArrayDeleteWantsSize,
PlacementArgs, TypeIdParens, ArraySize, initStyle,
@@ -2303,8 +2281,8 @@ static bool resolveAllocationOverload(
}
if (Diagnose) {
- S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
- << R.getLookupName() << Range;
+ PartialDiagnosticAt PD(R.getNameLoc(), S.PDiag(diag::err_ovl_no_viable_function_in_call)
+ << R.getLookupName() << Range);
// If we have aligned candidates, only note the align_val_t candidates
// from AlignedCandidates and the non-align_val_t candidates from
@@ -2319,31 +2297,34 @@ static bool resolveAllocationOverload(
// This was an overaligned allocation, so list the aligned candidates
// first.
Args.insert(Args.begin() + 1, AlignArg);
- AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "",
+ AlignedCandidates->NoteCandidates(PD, S, OCD_AllCandidates, Args, "",
R.getNameLoc(), IsAligned);
Args.erase(Args.begin() + 1);
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(),
+ Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args, "", R.getNameLoc(),
IsUnaligned);
} else {
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
+ Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args);
}
}
return true;
case OR_Ambiguous:
if (Diagnose) {
- S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call)
- << R.getLookupName() << Range;
- Candidates.NoteCandidates(S, OCD_ViableCandidates, Args);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(R.getNameLoc(),
+ S.PDiag(diag::err_ovl_ambiguous_call)
+ << R.getLookupName() << Range),
+ S, OCD_ViableCandidates, Args);
}
return true;
case OR_Deleted: {
if (Diagnose) {
- S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call)
- << Best->Function->isDeleted() << R.getLookupName()
- << S.getDeletedOrUnavailableSuffix(Best->Function) << Range;
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(R.getNameLoc(),
+ S.PDiag(diag::err_ovl_deleted_call)
+ << R.getLookupName() << Range),
+ S, OCD_AllCandidates, Args);
}
return true;
}
@@ -2432,7 +2413,11 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
}
if (getLangOpts().OpenCLCPlusPlus && R.empty()) {
- Diag(StartLoc, diag::err_openclcxx_not_supported) << "default new";
+ if (PlaceArgs.empty()) {
+ Diag(StartLoc, diag::err_openclcxx_not_supported) << "default new";
+ } else {
+ Diag(StartLoc, diag::err_openclcxx_placement_new);
+ }
return true;
}
@@ -2671,8 +2656,8 @@ void Sema::DeclareGlobalNewDelete() {
if (GlobalNewDeleteDeclared)
return;
- // OpenCL C++ 1.0 s2.9: the implicitly declared new and delete operators
- // are not supported.
+ // The implicitly declared new and delete operators
+ // are not supported in OpenCL.
if (getLangOpts().OpenCLCPlusPlus)
return;
@@ -2798,7 +2783,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
}
}
- FunctionProtoType::ExtProtoInfo EPI;
+ FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
+ /*IsVariadic=*/false, /*IsCXXMethod=*/false, /*IsBuiltin=*/true));
QualType BadAllocType;
bool HasBadAllocExceptionSpec
@@ -3506,22 +3492,26 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
}
case OR_No_Viable_Function:
- S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
- << R.getLookupName() << Range;
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(R.getNameLoc(),
+ S.PDiag(diag::err_ovl_no_viable_function_in_call)
+ << R.getLookupName() << Range),
+ S, OCD_AllCandidates, Args);
return true;
case OR_Ambiguous:
- S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call)
- << R.getLookupName() << Range;
- Candidates.NoteCandidates(S, OCD_ViableCandidates, Args);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(R.getNameLoc(),
+ S.PDiag(diag::err_ovl_ambiguous_call)
+ << R.getLookupName() << Range),
+ S, OCD_ViableCandidates, Args);
return true;
case OR_Deleted: {
- S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call)
- << Best->Function->isDeleted() << R.getLookupName()
- << S.getDeletedOrUnavailableSuffix(Best->Function) << Range;
- Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call)
+ << R.getLookupName() << Range),
+ S, OCD_AllCandidates, Args);
return true;
}
}
@@ -3647,12 +3637,9 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
diag::err_invalid_use_of_array_type)
<< ConditionVar->getSourceRange());
- ExprResult Condition = DeclRefExpr::Create(
- Context, NestedNameSpecifierLoc(), SourceLocation(), ConditionVar,
- /*enclosing*/ false, ConditionVar->getLocation(),
- ConditionVar->getType().getNonReferenceType(), VK_LValue);
-
- MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get()));
+ ExprResult Condition = BuildDeclRefExpr(
+ ConditionVar, ConditionVar->getType().getNonReferenceType(), VK_LValue,
+ ConditionVar->getLocation());
switch (CK) {
case ConditionKind::Boolean:
@@ -4229,7 +4216,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
case ICK_Block_Pointer_Conversion: {
- From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
+ LangAS AddrSpaceL =
+ ToType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceR =
+ FromType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace();
+ assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) &&
+ "Invalid cast");
+ CastKind Kind =
+ AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
+ From = ImpCastExprToType(From, ToType.getUnqualifiedType(), Kind,
VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
}
@@ -5096,8 +5091,15 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT)
== (lhsRecord == rhsRecord));
+ // Unions are never base classes, and never have base classes.
+ // It doesn't matter if they are complete or not. See PR#41843
+ if (lhsRecord && lhsRecord->getDecl()->isUnion())
+ return false;
+ if (rhsRecord && rhsRecord->getDecl()->isUnion())
+ return false;
+
if (lhsRecord == rhsRecord)
- return !lhsRecord->getDecl()->isUnion();
+ return true;
// C++0x [meta.rel]p2:
// If Base and Derived are class types and are different types
@@ -6019,6 +6021,8 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
if (EST2 == EST_NoexceptFalse) return ESI2;
// If either of them is non-throwing, the result is the other.
+ if (EST1 == EST_NoThrow) return ESI2;
+ if (EST2 == EST_NoThrow) return ESI1;
if (EST1 == EST_DynamicNone) return ESI2;
if (EST2 == EST_DynamicNone) return ESI1;
if (EST1 == EST_BasicNoexcept) return ESI2;
@@ -6047,6 +6051,7 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
case EST_DependentNoexcept:
case EST_NoexceptFalse:
case EST_NoexceptTrue:
+ case EST_NoThrow:
llvm_unreachable("handled above");
case EST_Dynamic: {
@@ -6765,9 +6770,12 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
FirstIteration = false;
}
- if (OpKind == tok::arrow &&
- (BaseType->isPointerType() || BaseType->isObjCObjectPointerType()))
- BaseType = BaseType->getPointeeType();
+ if (OpKind == tok::arrow) {
+ if (BaseType->isPointerType())
+ BaseType = BaseType->getPointeeType();
+ else if (auto *AT = Context.getAsArrayType(BaseType))
+ BaseType = AT->getElementType();
+ }
}
// Objective-C properties allow "." access on Objective-C pointer types,
@@ -6855,8 +6863,9 @@ canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef,
QualType DestructedType) {
// If this is a record type, check if its destructor is callable.
if (auto *RD = DestructedType->getAsCXXRecordDecl()) {
- if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD))
- return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false);
+ if (RD->hasDefinition())
+ if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD))
+ return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false);
return false;
}
@@ -7048,7 +7057,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
- TypeResult T = ActOnTemplateIdType(TemplateId->SS,
+ TypeResult T = ActOnTemplateIdType(S,
+ TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -7100,7 +7110,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
- TypeResult T = ActOnTemplateIdType(TemplateId->SS,
+ TypeResult T = ActOnTemplateIdType(S,
+ TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -7190,12 +7201,12 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
}
}
- MemberExpr *ME = new (Context) MemberExpr(
- Exp.get(), /*IsArrow=*/false, SourceLocation(), Method, SourceLocation(),
- Context.BoundMemberTy, VK_RValue, OK_Ordinary);
- if (HadMultipleCandidates)
- ME->setHadMultipleCandidates(true);
- MarkMemberReferenced(ME);
+ MemberExpr *ME =
+ BuildMemberExpr(Exp.get(), /*IsArrow=*/false, SourceLocation(),
+ NestedNameSpecifierLoc(), SourceLocation(), Method,
+ DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()),
+ HadMultipleCandidates, DeclarationNameInfo(),
+ Context.BoundMemberTy, VK_RValue, OK_Ordinary);
QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
@@ -7396,7 +7407,7 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,
return false;
}
- return !IsVariableAConstantExpression(Var, Context);
+ return !Var->isUsableInConstantExpressions(Context);
}
/// Check if the current lambda has any potential captures
@@ -7425,12 +7436,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
// All the potentially captureable variables in the current nested
// lambda (within a generic outer lambda), must be captured by an
// outer lambda that is enclosed within a non-dependent context.
- const unsigned NumPotentialCaptures =
- CurrentLSI->getNumPotentialVariableCaptures();
- for (unsigned I = 0; I != NumPotentialCaptures; ++I) {
- Expr *VarExpr = nullptr;
- VarDecl *Var = nullptr;
- CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
+ CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
// If the variable is clearly identified as non-odr-used and the full
// expression is not instantiation dependent, only then do we not
// need to check enclosing lambda's for speculative captures.
@@ -7444,17 +7450,15 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
// }
if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
!IsFullExprInstantiationDependent)
- continue;
+ return;
// If we have a capture-capable lambda for the variable, go ahead and
// capture the variable in that lambda (and all its enclosing lambdas).
if (const Optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
- S.FunctionScopes, Var, S)) {
- const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue();
- MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S,
- &FunctionScopeIndexOfCapturableLambda);
- }
+ S.FunctionScopes, Var, S))
+ S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(),
+ Index.getValue());
const bool IsVarNeverAConstantExpression =
VariableCanNeverBeAConstantExpression(Var, S.Context);
if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
@@ -7478,7 +7482,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
DeclRefType, nullptr);
}
}
- }
+ });
// Check if 'this' needs to be captured.
if (CurrentLSI->hasPotentialThisCapture()) {
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index b2b21ba9eefa..c856e37e99e7 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -1,9 +1,8 @@
//===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -591,7 +590,7 @@ namespace {
// Callback to only accept typo corrections that are either a ValueDecl or a
// FunctionTemplateDecl and are declared in the current record or, for a C++
// classes, one of its base classes.
-class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
+class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
public:
explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
: Record(RTy->getDecl()) {
@@ -629,6 +628,10 @@ public:
return false;
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<RecordMemberExprValidatorCCC>(*this);
+ }
+
private:
const RecordDecl *const Record;
};
@@ -697,9 +700,9 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
};
QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(),
R.redeclarationKind()};
+ RecordMemberExprValidatorCCC CCC(RTy);
TE = SemaRef.CorrectTypoDelayed(
- R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS,
- llvm::make_unique<RecordMemberExprValidatorCCC>(RTy),
+ R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, CCC,
[=, &SemaRef](const TypoCorrection &TC) {
if (TC) {
assert(!TC.isKeyword() &&
@@ -890,18 +893,32 @@ BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
NameInfo.getLoc());
}
-/// Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(
- Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow,
- SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- ValueDecl *Member, DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK,
- ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr) {
- assert((!isArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
- MemberExpr *E = MemberExpr::Create(
- C, Base, isArrow, OpLoc, SS.getWithLocInContext(C), TemplateKWLoc, Member,
- FoundDecl, MemberNameInfo, TemplateArgs, Ty, VK, OK);
- SemaRef.MarkMemberReferenced(E);
+MemberExpr *Sema::BuildMemberExpr(
+ Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS,
+ SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
+ bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
+ QualType Ty, ExprValueKind VK, ExprObjectKind OK,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ NestedNameSpecifierLoc NNS =
+ SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc();
+ return BuildMemberExpr(Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member,
+ FoundDecl, HadMultipleCandidates, MemberNameInfo, Ty,
+ VK, OK, TemplateArgs);
+}
+
+MemberExpr *Sema::BuildMemberExpr(
+ Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
+ bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
+ QualType Ty, ExprValueKind VK, ExprObjectKind OK,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert((!IsArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
+ MemberExpr *E =
+ MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc,
+ Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty,
+ VK, OK, getNonOdrUseReasonInCurrentContext(Member));
+ E->setHadMultipleCandidates(HadMultipleCandidates);
+ MarkMemberReferenced(E);
return E;
}
@@ -1089,8 +1106,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
- CheckCXXThisCapture(Loc);
- BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
+ BaseExpr = BuildCXXThisExpr(Loc, BaseExprType, /*IsImplicit=*/true);
}
// Check the use of this member.
@@ -1113,10 +1129,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
- TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
- Var->getType().getNonReferenceType(), VK_LValue,
- OK_Ordinary);
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var,
+ FoundDecl, /*HadMultipleCandidates=*/false,
+ MemberNameInfo, Var->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary);
}
if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
@@ -1130,24 +1146,25 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
type = MemberFn->getType();
}
- return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
- TemplateKWLoc, MemberFn, FoundDecl, MemberNameInfo,
- type, valueKind, OK_Ordinary);
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc,
+ MemberFn, FoundDecl, /*HadMultipleCandidates=*/false,
+ MemberNameInfo, type, valueKind, OK_Ordinary);
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
- TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
- Enum->getType(), VK_RValue, OK_Ordinary);
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum,
+ FoundDecl, /*HadMultipleCandidates=*/false,
+ 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 BuildMemberExpr(
+ BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
+ /*HadMultipleCandidates=*/false, MemberNameInfo,
+ Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
return ExprError();
}
@@ -1332,11 +1349,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (!IV) {
// Attempt to correct for typos in ivar names.
- auto Validator = llvm::make_unique<DeclFilterCCC<ObjCIvarDecl>>();
- Validator->IsObjCIvarLookup = IsArrow;
+ DeclFilterCCC<ObjCIvarDecl> Validator{};
+ Validator.IsObjCIvarLookup = IsArrow;
if (TypoCorrection Corrected = S.CorrectTypo(
R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr,
- std::move(Validator), Sema::CTK_ErrorRecovery, IDecl)) {
+ Validator, Sema::CTK_ErrorRecovery, IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
S.diagnoseTypo(
Corrected,
@@ -1803,9 +1820,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
}
}
- return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
+ return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS,
/*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
- MemberNameInfo, MemberType, VK, OK);
+ /*HadMultipleCandidates=*/false, MemberNameInfo,
+ MemberType, VK, OK);
}
/// Builds an implicit member access expression. The current context
@@ -1833,8 +1851,7 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
- CheckCXXThisCapture(Loc);
- baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
+ baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true);
}
return BuildMemberReferenceExpr(baseExpr, ThisTy,
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index ed780efd4cf3..040cfdd30c7a 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1,9 +1,8 @@
//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -26,6 +25,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ConvertUTF.h"
using namespace clang;
using namespace sema;
@@ -525,6 +525,30 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
NSStringPointer = Context.getObjCObjectPointerType(NSStringObject);
}
+ // The boxed expression can be emitted as a compile time constant if it is
+ // a string literal whose character encoding is compatible with UTF-8.
+ if (auto *CE = dyn_cast<ImplicitCastExpr>(ValueExpr))
+ if (CE->getCastKind() == CK_ArrayToPointerDecay)
+ if (auto *SL =
+ dyn_cast<StringLiteral>(CE->getSubExpr()->IgnoreParens())) {
+ assert((SL->isAscii() || SL->isUTF8()) &&
+ "unexpected character encoding");
+ StringRef Str = SL->getString();
+ const llvm::UTF8 *StrBegin = Str.bytes_begin();
+ const llvm::UTF8 *StrEnd = Str.bytes_end();
+ // Check that this is a valid UTF-8 string.
+ if (llvm::isLegalUTF8String(&StrBegin, StrEnd)) {
+ BoxedType = Context.getAttributedType(
+ AttributedType::getNullabilityAttrKind(
+ NullabilityKind::NonNull),
+ NSStringPointer, NSStringPointer);
+ return new (Context) ObjCBoxedExpr(CE, BoxedType, nullptr, SR);
+ }
+
+ Diag(SL->getBeginLoc(), diag::warn_objc_boxing_invalid_utf8_string)
+ << NSStringPointer << SL->getSourceRange();
+ }
+
if (!StringWithUTF8StringMethod) {
IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String");
Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II);
@@ -1073,12 +1097,7 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
// The type of @encode is the same as the type of the corresponding string,
// which is an array type.
- StrTy = Context.CharTy;
- // A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
- if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings)
- StrTy.addConst();
- StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
- ArrayType::Normal, 0);
+ StrTy = Context.getStringLiteralArrayType(Context.CharTy, Str.size());
}
return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc);
@@ -1922,11 +1941,10 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
// Attempt to correct for typos in property names.
- if (TypoCorrection Corrected =
- CorrectTypo(DeclarationNameInfo(MemberName, MemberLoc),
- LookupOrdinaryName, nullptr, nullptr,
- llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(),
- CTK_ErrorRecovery, IFace, false, OPT)) {
+ DeclFilterCCC<ObjCPropertyDecl> CCC{};
+ if (TypoCorrection Corrected = CorrectTypo(
+ DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName,
+ nullptr, nullptr, CCC, CTK_ErrorRecovery, IFace, false, OPT)) {
DeclarationName TypoResult = Corrected.getCorrection();
if (TypoResult.isIdentifier() &&
TypoResult.getAsIdentifierInfo() == Member) {
@@ -2083,7 +2101,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
namespace {
-class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback {
+class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback {
public:
ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) {
// Determine whether "super" is acceptable in the current context.
@@ -2095,6 +2113,10 @@ class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback {
return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() ||
candidate.isKeyword("super");
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<ObjCInterfaceOrSuperCCC>(*this);
+ }
};
} // end anonymous namespace
@@ -2170,9 +2192,9 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
}
}
+ ObjCInterfaceOrSuperCCC CCC(getCurMethodDecl());
if (TypoCorrection Corrected = CorrectTypo(
- Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr,
- llvm::make_unique<ObjCInterfaceOrSuperCCC>(getCurMethodDecl()),
+ Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, CCC,
CTK_ErrorRecovery, nullptr, false, nullptr, false)) {
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
@@ -2806,8 +2828,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
} else {
if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
- // FIXME: Is this correct? Why are we assuming that a message to
- // Class will call a method in the current interface?
+ // As a guess, try looking for the method in the current interface.
+ // This very well may not produce the "right" method.
// First check the public methods in the class interface.
Method = ClassDecl->lookupClassMethod(Sel);
@@ -2815,8 +2837,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method)
Method = ClassDecl->lookupPrivateClassMethod(Sel);
- if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, nullptr,
- false, false, ClassDecl))
+ if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs))
return ExprError();
}
}
@@ -4333,23 +4354,22 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
assert(!gse->isResultDependent());
unsigned n = gse->getNumAssocs();
- SmallVector<Expr*, 4> subExprs(n);
- SmallVector<TypeSourceInfo*, 4> subTypes(n);
- for (unsigned i = 0; i != n; ++i) {
- subTypes[i] = gse->getAssocTypeSourceInfo(i);
- Expr *sub = gse->getAssocExpr(i);
- if (i == gse->getResultIndex())
+ SmallVector<Expr *, 4> subExprs;
+ SmallVector<TypeSourceInfo *, 4> subTypes;
+ subExprs.reserve(n);
+ subTypes.reserve(n);
+ for (const GenericSelectionExpr::Association &assoc : gse->associations()) {
+ subTypes.push_back(assoc.getTypeSourceInfo());
+ Expr *sub = assoc.getAssociationExpr();
+ if (assoc.isSelected())
sub = stripARCUnbridgedCast(sub);
- subExprs[i] = sub;
+ subExprs.push_back(sub);
}
- return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(),
- gse->getControllingExpr(),
- subTypes, subExprs,
- gse->getDefaultLoc(),
- gse->getRParenLoc(),
- gse->containsUnexpandedParameterPack(),
- gse->getResultIndex());
+ return GenericSelectionExpr::Create(
+ Context, gse->getGenericLoc(), gse->getControllingExpr(), subTypes,
+ subExprs, gse->getDefaultLoc(), gse->getRParenLoc(),
+ gse->containsUnexpandedParameterPack(), gse->getResultIndex());
} else {
assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!");
return cast<ImplicitCastExpr>(e)->getSubExpr();
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index 714fbedf09bc..41a7a90a3727 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -1,9 +1,8 @@
//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 10c0c6bf33b3..bc1069609336 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1,9 +1,8 @@
//===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -145,16 +144,43 @@ static StringInitFailureKind IsStringInit(Expr *init, QualType declType,
static void updateStringLiteralType(Expr *E, QualType Ty) {
while (true) {
E->setType(Ty);
- if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E))
+ E->setValueKind(VK_RValue);
+ if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) {
break;
- else if (ParenExpr *PE = dyn_cast<ParenExpr>(E))
+ } else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
E = PE->getSubExpr();
- else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+ } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ assert(UO->getOpcode() == UO_Extension);
E = UO->getSubExpr();
- else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E))
+ } else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) {
E = GSE->getResultExpr();
- else
+ } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
+ E = CE->getChosenSubExpr();
+ } else {
llvm_unreachable("unexpected expr in string literal init");
+ }
+ }
+}
+
+/// Fix a compound literal initializing an array so it's correctly marked
+/// as an rvalue.
+static void updateGNUCompoundLiteralRValue(Expr *E) {
+ while (true) {
+ E->setValueKind(VK_RValue);
+ if (isa<CompoundLiteralExpr>(E)) {
+ break;
+ } else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ E = PE->getSubExpr();
+ } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ assert(UO->getOpcode() == UO_Extension);
+ E = UO->getSubExpr();
+ } else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) {
+ E = GSE->getResultExpr();
+ } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) {
+ E = CE->getChosenSubExpr();
+ } else {
+ llvm_unreachable("unexpected expr in array compound literal init");
+ }
}
}
@@ -1681,6 +1707,30 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
}
+/// Check if the type of a class element has an accessible destructor, and marks
+/// it referenced. Returns true if we shouldn't form a reference to the
+/// destructor.
+///
+/// Aggregate initialization requires a class element's destructor be
+/// accessible per 11.6.1 [dcl.init.aggr]:
+///
+/// The destructor for each element of class type is potentially invoked
+/// (15.4 [class.dtor]) from the context where the aggregate initialization
+/// occurs.
+static bool checkDestructorReference(QualType ElementType, SourceLocation Loc,
+ Sema &SemaRef) {
+ auto *CXXRD = ElementType->getAsCXXRecordDecl();
+ if (!CXXRD)
+ return false;
+
+ CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
+ SemaRef.CheckDestructorAccess(Loc, Destructor,
+ SemaRef.PDiag(diag::err_access_dtor_temp)
+ << ElementType);
+ SemaRef.MarkFunctionReferenced(Loc, Destructor);
+ return SemaRef.DiagnoseUseOfDecl(Destructor, Loc);
+}
+
void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
@@ -1690,6 +1740,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
unsigned &StructuredIndex) {
const ArrayType *arrayType = SemaRef.Context.getAsArrayType(DeclType);
+ if (!VerifyOnly) {
+ if (checkDestructorReference(arrayType->getElementType(),
+ IList->getEndLoc(), SemaRef)) {
+ hadError = true;
+ return;
+ }
+ }
+
// Check for the special-case of initializing an array with a string.
if (Index < IList->getNumInits()) {
if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) ==
@@ -1851,30 +1909,6 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
return FlexArrayDiag != diag::ext_flexible_array_init;
}
-/// Check if the type of a class element has an accessible destructor.
-///
-/// Aggregate initialization requires a class element's destructor be
-/// accessible per 11.6.1 [dcl.init.aggr]:
-///
-/// The destructor for each element of class type is potentially invoked
-/// (15.4 [class.dtor]) from the context where the aggregate initialization
-/// occurs.
-static bool hasAccessibleDestructor(QualType ElementType, SourceLocation Loc,
- Sema &SemaRef) {
- auto *CXXRD = ElementType->getAsCXXRecordDecl();
- if (!CXXRD)
- return false;
-
- CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD);
- SemaRef.CheckDestructorAccess(Loc, Destructor,
- SemaRef.PDiag(diag::err_access_dtor_temp)
- << ElementType);
- SemaRef.MarkFunctionReferenced(Loc, Destructor);
- if (SemaRef.DiagnoseUseOfDecl(Destructor, Loc))
- return true;
- return false;
-}
-
void InitListChecker::CheckStructUnionTypes(
const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
@@ -1898,7 +1932,7 @@ void InitListChecker::CheckStructUnionTypes(
if (!VerifyOnly)
for (FieldDecl *FD : RD->fields()) {
QualType ET = SemaRef.Context.getBaseElementType(FD->getType());
- if (hasAccessibleDestructor(ET, IList->getEndLoc(), SemaRef)) {
+ if (checkDestructorReference(ET, IList->getEndLoc(), SemaRef)) {
hadError = true;
return;
}
@@ -1958,7 +1992,7 @@ void InitListChecker::CheckStructUnionTypes(
}
if (!VerifyOnly)
- if (hasAccessibleDestructor(Base.getType(), InitLoc, SemaRef)) {
+ if (checkDestructorReference(Base.getType(), InitLoc, SemaRef)) {
hadError = true;
return;
}
@@ -2000,7 +2034,7 @@ void InitListChecker::CheckStructUnionTypes(
while (std::next(F) != Field)
++F;
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
- if (hasAccessibleDestructor(ET, InitLoc, SemaRef)) {
+ if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;
}
@@ -2049,7 +2083,7 @@ void InitListChecker::CheckStructUnionTypes(
if (!VerifyOnly) {
QualType ET = SemaRef.Context.getBaseElementType(Field->getType());
- if (hasAccessibleDestructor(ET, InitLoc, SemaRef)) {
+ if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;
}
@@ -2105,7 +2139,7 @@ void InitListChecker::CheckStructUnionTypes(
: Field;
for (RecordDecl::field_iterator E = RD->field_end(); I != E; ++I) {
QualType ET = SemaRef.Context.getBaseElementType(I->getType());
- if (hasAccessibleDestructor(ET, IList->getEndLoc(), SemaRef)) {
+ if (checkDestructorReference(ET, IList->getEndLoc(), SemaRef)) {
hadError = true;
return;
}
@@ -2182,7 +2216,7 @@ namespace {
// Callback to only accept typo corrections that are for field members of
// the given struct or union.
-class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
+class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
public:
explicit FieldInitializerValidatorCCC(RecordDecl *RD)
: Record(RD) {}
@@ -2192,6 +2226,10 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record);
}
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<FieldInitializerValidatorCCC>(*this);
+ }
+
private:
RecordDecl *Record;
};
@@ -2394,10 +2432,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Name lookup didn't find anything.
// Determine whether this was a typo for another field name.
+ FieldInitializerValidatorCCC CCC(RT->getDecl());
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
- Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr,
- llvm::make_unique<FieldInitializerValidatorCCC>(RT->getDecl()),
+ Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, CCC,
Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
@@ -3244,7 +3282,6 @@ void InitializationSequence::Step::Destroy() {
case SK_QualificationConversionXValue:
case SK_QualificationConversionLValue:
case SK_AtomicConversion:
- case SK_LValueToRValue:
case SK_ListInitialization:
case SK_UnwrapInitList:
case SK_RewrapInitList:
@@ -3306,6 +3343,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_NonConstLValueReferenceBindingToVectorElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
+ case FK_ReferenceAddrspaceMismatchTemporary:
case FK_ReferenceInitDropsQualifiers:
case FK_ReferenceInitFailed:
case FK_ConversionFailed:
@@ -3427,15 +3465,6 @@ void InitializationSequence::AddAtomicConversionStep(QualType Ty) {
Steps.push_back(S);
}
-void InitializationSequence::AddLValueToRValueStep(QualType Ty) {
- assert(!Ty.hasQualifiers() && "rvalues may not have qualifiers");
-
- Step S;
- S.Kind = SK_LValueToRValue;
- S.Type = Ty;
- Steps.push_back(S);
-}
-
void InitializationSequence::AddConversionSequenceStep(
const ImplicitConversionSequence &ICS, QualType T,
bool TopLevelOfInitList) {
@@ -3704,6 +3733,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
bool OnlyListConstructors, bool IsListInit,
bool SecondStepOfCopyInit = false) {
CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
+ CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace());
for (NamedDecl *D : Ctors) {
auto Info = getConstructorInfo(D);
@@ -3733,9 +3763,10 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
hasCopyOrMoveCtorParam(S.Context, Info));
if (Info.ConstructorTmpl)
- S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
- /*ExplicitArgs*/ nullptr, Args,
- CandidateSet, SuppressUserConversions);
+ S.AddTemplateOverloadCandidate(
+ Info.ConstructorTmpl, Info.FoundDecl,
+ /*ExplicitArgs*/ nullptr, Args, CandidateSet, SuppressUserConversions,
+ /*PartialOverloading=*/false, AllowExplicit);
else {
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
@@ -3749,8 +3780,8 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
hasCopyOrMoveCtorParam(S.Context, Info);
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
CandidateSet, SuppressUserConversions,
- /*PartialOverloading=*/false,
- /*AllowExplicit=*/AllowExplicitConv);
+ /*PartialOverloading=*/false, AllowExplicit,
+ AllowExplicitConv);
}
}
@@ -3783,16 +3814,17 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
else
Conv = cast<CXXConversionDecl>(D);
- if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
+ if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
- ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit,
- /*AllowResultConversion*/false);
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit,
+ /*AllowResultConversion*/ false);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
DestType, CandidateSet, AllowExplicit,
- /*AllowResultConversion*/false);
+ AllowExplicit,
+ /*AllowResultConversion*/ false);
}
}
}
@@ -3899,7 +3931,7 @@ static void TryConstructorInitialization(Sema &S,
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
- /*OnlyListConstructor=*/true,
+ /*OnlyListConstructors=*/true,
IsListInit);
}
@@ -4086,7 +4118,7 @@ static void TryReferenceListInitialization(Sema &S,
if (Sequence) {
if (DestType->isRValueReferenceType() ||
(T1Quals.hasConst() && !T1Quals.hasVolatile()))
- Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+ Sequence.AddReferenceBindingStep(cv1T1, /*BindingTemporary=*/true);
else
Sequence.SetFailed(
InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
@@ -4338,14 +4370,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
if (Info.ConstructorTmpl)
- S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
- /*ExplicitArgs*/ nullptr,
- Initializer, CandidateSet,
- /*SuppressUserConversions=*/true);
+ S.AddTemplateOverloadCandidate(
+ Info.ConstructorTmpl, Info.FoundDecl,
+ /*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
+ /*SuppressUserConversions=*/true,
+ /*PartialOverloading*/ false, AllowExplicitCtors);
else
- S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
- Initializer, CandidateSet,
- /*SuppressUserConversions=*/true);
+ S.AddOverloadCandidate(
+ Info.Constructor, Info.FoundDecl, Initializer, CandidateSet,
+ /*SuppressUserConversions=*/true,
+ /*PartialOverloading*/ false, AllowExplicitCtors);
}
}
}
@@ -4380,17 +4414,17 @@ static OverloadingResult TryRefInitWithConversionFunction(
// candidates with reference-compatible results? That might be needed to
// break recursion.
if ((AllowExplicitConvs || !Conv->isExplicit()) &&
- (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
+ (AllowRValues ||
+ Conv->getConversionType()->isLValueReferenceType())) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
- ActingDC, Initializer,
- DestType, CandidateSet,
- /*AllowObjCConversionOnExplicit=*/
- false);
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
- Initializer, DestType, CandidateSet,
- /*AllowObjCConversionOnExplicit=*/false);
+ S.AddConversionCandidate(
+ Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
}
}
}
@@ -4597,7 +4631,10 @@ static void TryReferenceInitializationCore(Sema &S,
// - Otherwise, the reference shall be an lvalue reference to a
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference.
- if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile())) {
+ // For address spaces, we interpret this to mean that an addr space
+ // of a reference "cv1 T1" is a superset of addr space of "cv2 T2".
+ if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile() &&
+ T1Quals.isAddressSpaceSupersetOf(T2Quals))) {
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
@@ -4606,7 +4643,10 @@ static void TryReferenceInitializationCore(Sema &S,
ConvOvlResult);
else if (!InitCategory.isLValue())
Sequence.SetFailed(
- InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary);
+ T1Quals.isAddressSpaceSupersetOf(T2Quals)
+ ? InitializationSequence::
+ FK_NonConstLValueReferenceBindingToTemporary
+ : InitializationSequence::FK_ReferenceInitDropsQualifiers);
else {
InitializationSequence::FailureKind FK;
switch (RefRelationship) {
@@ -4671,19 +4711,23 @@ static void TryReferenceInitializationCore(Sema &S,
// applied.
// Postpone address space conversions to after the temporary materialization
// conversion to allow creating temporaries in the alloca address space.
- auto AS1 = T1Quals.getAddressSpace();
- auto AS2 = T2Quals.getAddressSpace();
- T1Quals.removeAddressSpace();
- T2Quals.removeAddressSpace();
- QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1Quals);
- if (T1Quals != T2Quals)
+ auto T1QualsIgnoreAS = T1Quals;
+ auto T2QualsIgnoreAS = T2Quals;
+ if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) {
+ T1QualsIgnoreAS.removeAddressSpace();
+ T2QualsIgnoreAS.removeAddressSpace();
+ }
+ QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1QualsIgnoreAS);
+ if (T1QualsIgnoreAS != T2QualsIgnoreAS)
Sequence.AddQualificationConversionStep(cv1T4, ValueKind);
Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_RValue);
ValueKind = isLValueRef ? VK_LValue : VK_XValue;
- if (AS1 != AS2) {
- T1Quals.addAddressSpace(AS1);
- QualType cv1AST4 = S.Context.getQualifiedType(cv2T2, T1Quals);
- Sequence.AddQualificationConversionStep(cv1AST4, ValueKind);
+ // Add addr space conversion if required.
+ if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) {
+ auto T4Quals = cv1T4.getQualifiers();
+ T4Quals.addAddressSpace(T1Quals.getAddressSpace());
+ QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals);
+ Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
}
// In any case, the reference is bound to the resulting glvalue (or to
@@ -4730,7 +4774,15 @@ static void TryReferenceInitializationCore(Sema &S,
// copy-initialization (8.5). The reference is then bound to the
// temporary. [...]
- InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
+ // Ignore address space of reference type at this point and perform address
+ // space conversion after the reference binding step.
+ QualType cv1T1IgnoreAS =
+ T1Quals.hasAddressSpace()
+ ? S.Context.getQualifiedType(T1, T1Quals.withoutAddressSpace())
+ : cv1T1;
+
+ InitializedEntity TempEntity =
+ InitializedEntity::InitializeTemporary(cv1T1IgnoreAS);
// FIXME: Why do we use an implicit conversion here rather than trying
// copy-initialization?
@@ -4765,8 +4817,9 @@ static void TryReferenceInitializationCore(Sema &S,
// than, cv2; otherwise, the program is ill-formed.
unsigned T1CVRQuals = T1Quals.getCVRQualifiers();
unsigned T2CVRQuals = T2Quals.getCVRQualifiers();
- if (RefRelationship == Sema::Ref_Related &&
- (T1CVRQuals | T2CVRQuals) != T1CVRQuals) {
+ if ((RefRelationship == Sema::Ref_Related &&
+ (T1CVRQuals | T2CVRQuals) != T1CVRQuals) ||
+ !T1Quals.isAddressSpaceSupersetOf(T2Quals)) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
@@ -4780,7 +4833,18 @@ static void TryReferenceInitializationCore(Sema &S,
return;
}
- Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
+ Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*BindingTemporary=*/true);
+
+ if (T1Quals.hasAddressSpace()) {
+ if (!Qualifiers::isAddressSpaceSupersetOf(T1Quals.getAddressSpace(),
+ LangAS::Default)) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_ReferenceAddrspaceMismatchTemporary);
+ return;
+ }
+ Sequence.AddQualificationConversionStep(cv1T1, isLValueRef ? VK_LValue
+ : VK_XValue);
+ }
}
/// Attempt character array initialization from a string literal
@@ -4928,6 +4992,7 @@ static void TryUserDefinedConversion(Sema &S,
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
+ CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace());
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
@@ -4949,14 +5014,16 @@ static void TryUserDefinedConversion(Sema &S,
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(AllowExplicit)) {
if (Info.ConstructorTmpl)
- S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
- /*ExplicitArgs*/ nullptr,
- Initializer, CandidateSet,
- /*SuppressUserConversions=*/true);
+ S.AddTemplateOverloadCandidate(
+ Info.ConstructorTmpl, Info.FoundDecl,
+ /*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
+ /*SuppressUserConversions=*/true,
+ /*PartialOverloading*/ false, AllowExplicit);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
Initializer, CandidateSet,
- /*SuppressUserConversions=*/true);
+ /*SuppressUserConversions=*/true,
+ /*PartialOverloading*/ false, AllowExplicit);
}
}
}
@@ -4991,12 +5058,12 @@ static void TryUserDefinedConversion(Sema &S,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
- ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit);
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit);
else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
- Initializer, DestType, CandidateSet,
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
AllowExplicit);
}
}
@@ -5538,8 +5605,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// array from a compound literal that creates an array of the same
// type, so long as the initializer has no side effects.
if (!S.getLangOpts().CPlusPlus && Initializer &&
- (isa<ConstantExpr>(Initializer->IgnoreParens()) ||
- isa<CompoundLiteralExpr>(Initializer->IgnoreParens())) &&
+ isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) &&
Initializer->getType()->isArrayType()) {
const ArrayType *SourceAT
= Context.getAsArrayType(Initializer->getType());
@@ -5574,6 +5640,9 @@ void InitializationSequence::InitializeFrom(Sema &S,
bool allowObjCWritebackConversion = S.getLangOpts().ObjCAutoRefCount &&
Entity.isParameterKind();
+ if (TryOCLSamplerInitialization(S, *this, DestType, Initializer))
+ return;
+
// We're at the end of the line for C: it's either a write-back conversion
// or it's a C assignment. There's no need to check anything else.
if (!S.getLangOpts().CPlusPlus) {
@@ -5583,9 +5652,6 @@ void InitializationSequence::InitializeFrom(Sema &S,
return;
}
- if (TryOCLSamplerInitialization(S, *this, DestType, Initializer))
- return;
-
if (TryOCLZeroOpaqueTypeInitialization(S, *this, DestType, Initializer))
return;
@@ -5925,21 +5991,25 @@ static ExprResult CopyObject(Sema &S,
break;
case OR_No_Viable_Function:
- S.Diag(Loc, IsExtraneousCopy && !S.isSFINAEContext()
- ? diag::ext_rvalue_to_reference_temp_copy_no_viable
- : diag::err_temp_copy_no_viable)
- << (int)Entity.getKind() << CurInitExpr->getType()
- << CurInitExpr->getSourceRange();
- CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ Loc, S.PDiag(IsExtraneousCopy && !S.isSFINAEContext()
+ ? diag::ext_rvalue_to_reference_temp_copy_no_viable
+ : diag::err_temp_copy_no_viable)
+ << (int)Entity.getKind() << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange()),
+ S, OCD_AllCandidates, CurInitExpr);
if (!IsExtraneousCopy || S.isSFINAEContext())
return ExprError();
return CurInit;
case OR_Ambiguous:
- S.Diag(Loc, diag::err_temp_copy_ambiguous)
- << (int)Entity.getKind() << CurInitExpr->getType()
- << CurInitExpr->getSourceRange();
- CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Loc, S.PDiag(diag::err_temp_copy_ambiguous)
+ << (int)Entity.getKind()
+ << CurInitExpr->getType()
+ << CurInitExpr->getSourceRange()),
+ S, OCD_ViableCandidates, CurInitExpr);
return ExprError();
case OR_Deleted:
@@ -6074,13 +6144,13 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
break;
case OR_No_Viable_Function:
- S.Diag(Loc, Diag);
- CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
+ CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
+ OCD_AllCandidates, CurInitExpr);
break;
case OR_Ambiguous:
- S.Diag(Loc, Diag);
- CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr);
+ CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
+ OCD_ViableCandidates, CurInitExpr);
break;
case OR_Deleted:
@@ -6269,6 +6339,10 @@ PerformConstructorInitialization(Sema &S,
if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
+ if (const ArrayType *AT = S.Context.getAsArrayType(Entity.getType()))
+ if (checkDestructorReference(S.Context.getBaseElementType(AT), Loc, S))
+ return ExprError();
+
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.get());
@@ -6784,6 +6858,9 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
RK_ReferenceBinding, Visit);
else {
unsigned Index = 0;
+ for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index)
+ visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit,
+ RevisitSubinits);
for (const auto *I : RD->fields()) {
if (Index >= ILE->getNumInits())
break;
@@ -7275,9 +7352,19 @@ ExprResult Sema::TemporaryMaterializationConversion(Expr *E) {
ExprResult Sema::PerformQualificationConversion(Expr *E, QualType Ty,
ExprValueKind VK,
CheckedConversionKind CCK) {
- CastKind CK = (Ty.getAddressSpace() != E->getType().getAddressSpace())
- ? CK_AddressSpaceConversion
- : CK_NoOp;
+
+ CastKind CK = CK_NoOp;
+
+ if (VK == VK_RValue) {
+ auto PointeeTy = Ty->getPointeeType();
+ auto ExprPointeeTy = E->getType()->getPointeeType();
+ if (!PointeeTy.isNull() &&
+ PointeeTy.getAddressSpace() != ExprPointeeTy.getAddressSpace())
+ CK = CK_AddressSpaceConversion;
+ } else if (Ty.getAddressSpace() != E->getType().getAddressSpace()) {
+ CK = CK_AddressSpaceConversion;
+ }
+
return ImpCastExprToType(E, Ty, CK, VK, /*BasePath=*/nullptr, CCK);
}
@@ -7416,7 +7503,6 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
case SK_AtomicConversion:
- case SK_LValueToRValue:
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing:
case SK_ListInitialization:
@@ -7688,14 +7774,6 @@ ExprResult InitializationSequence::Perform(Sema &S,
break;
}
- case SK_LValueToRValue: {
- assert(CurInit.get()->isGLValue() && "cannot load from a prvalue");
- CurInit = ImplicitCastExpr::Create(S.Context, Step->Type,
- CK_LValueToRValue, CurInit.get(),
- /*BasePath=*/nullptr, VK_RValue);
- break;
- }
-
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing: {
if (const auto *FromPtrType =
@@ -7952,6 +8030,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
S.Diag(Kind.getLocation(), diag::ext_array_init_copy)
<< Step->Type << CurInit.get()->getType()
<< CurInit.get()->getSourceRange();
+ updateGNUCompoundLiteralRValue(CurInit.get());
LLVM_FALLTHROUGH;
case SK_ArrayInit:
// If the destination type is an incomplete array type, update the
@@ -8342,19 +8421,22 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
case OR_Ambiguous:
- if (Failure == FK_UserConversionOverloadFailed)
- S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
- << OnlyArg->getType() << DestType
- << Args[0]->getSourceRange();
- else
- S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous)
- << DestType << OnlyArg->getType()
- << Args[0]->getSourceRange();
- FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args);
+ FailedCandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ Kind.getLocation(),
+ Failure == FK_UserConversionOverloadFailed
+ ? (S.PDiag(diag::err_typecheck_ambiguous_condition)
+ << OnlyArg->getType() << DestType
+ << Args[0]->getSourceRange())
+ : (S.PDiag(diag::err_ref_init_ambiguous)
+ << DestType << OnlyArg->getType()
+ << Args[0]->getSourceRange())),
+ S, OCD_ViableCandidates, Args);
break;
- case OR_No_Viable_Function:
+ case OR_No_Viable_Function: {
+ auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args);
if (!S.RequireCompleteType(Kind.getLocation(),
DestType.getNonReferenceType(),
diag::err_typecheck_nonviable_condition_incomplete,
@@ -8364,9 +8446,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< OnlyArg->getType() << Args[0]->getSourceRange()
<< DestType.getNonReferenceType();
- FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args);
+ FailedCandidateSet.NoteCandidates(S, Args, Cands);
break;
-
+ }
case OR_Deleted: {
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
@@ -8434,23 +8516,34 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
+ case FK_ReferenceAddrspaceMismatchTemporary:
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_temporary_addrspace)
+ << DestType << Args[0]->getSourceRange();
+ break;
+
case FK_ReferenceInitDropsQualifiers: {
QualType SourceType = OnlyArg->getType();
QualType NonRefType = DestType.getNonReferenceType();
Qualifiers DroppedQualifiers =
SourceType.getQualifiers() - NonRefType.getQualifiers();
- S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
- << SourceType
- << NonRefType
- << DroppedQualifiers.getCVRQualifiers()
- << Args[0]->getSourceRange();
+ if (!NonRefType.getQualifiers().isAddressSpaceSupersetOf(
+ SourceType.getQualifiers()))
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+ << NonRefType << SourceType << 1 /*addr space*/
+ << Args[0]->getSourceRange();
+ else
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+ << NonRefType << SourceType << 0 /*cv quals*/
+ << Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
+ << DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
break;
}
case FK_ReferenceInitFailed:
S.Diag(Kind.getLocation(), diag::err_reference_bind_failed)
<< DestType.getNonReferenceType()
+ << DestType.getNonReferenceType()->isIncompleteType()
<< OnlyArg->isLValue()
<< OnlyArg->getType()
<< Args[0]->getSourceRange();
@@ -8529,9 +8622,11 @@ bool InitializationSequence::Diagnose(Sema &S,
// bad.
switch (FailedOverloadResult) {
case OR_Ambiguous:
- S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
- << DestType << ArgsRange;
- FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args);
+ FailedCandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Kind.getLocation(),
+ S.PDiag(diag::err_ovl_ambiguous_init)
+ << DestType << ArgsRange),
+ S, OCD_ViableCandidates, Args);
break;
case OR_No_Viable_Function:
@@ -8580,9 +8675,12 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
- S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
- << DestType << ArgsRange;
- FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args);
+ FailedCandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ Kind.getLocation(),
+ S.PDiag(diag::err_ovl_no_viable_function_in_init)
+ << DestType << ArgsRange),
+ S, OCD_AllCandidates, Args);
break;
case OR_Deleted: {
@@ -8591,7 +8689,7 @@ bool InitializationSequence::Diagnose(Sema &S,
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl != OR_Deleted) {
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
- << true << DestType << ArgsRange;
+ << DestType << ArgsRange;
llvm_unreachable("Inconsistent overload resolution?");
break;
}
@@ -8605,7 +8703,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< DestType << ArgsRange;
else
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
- << true << DestType << ArgsRange;
+ << DestType << ArgsRange;
S.NoteDeletedFunction(Best->Function);
break;
@@ -8763,6 +8861,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "reference initialization drops qualifiers";
break;
+ case FK_ReferenceAddrspaceMismatchTemporary:
+ OS << "reference with mismatching address space bound to temporary";
+ break;
+
case FK_ReferenceInitFailed:
OS << "reference initialization failed";
break;
@@ -8898,10 +9000,6 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "non-atomic-to-atomic conversion";
break;
- case SK_LValueToRValue:
- OS << "load (lvalue to rvalue)";
- break;
-
case SK_ConversionSequence:
OS << "implicit conversion sequence (";
S->ICS->dump(); // FIXME: use OS
@@ -9264,9 +9362,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
OverloadCandidateSet Candidates(Kind.getLocation(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
+
+ bool HasAnyDeductionGuide = false;
+ bool AllowExplicit = !Kind.isCopyInit() || ListInit;
+
auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
Candidates.clear(OverloadCandidateSet::CSK_Normal);
+ HasAnyDeductionGuide = false;
+
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (D->isInvalidDecl())
@@ -9278,12 +9382,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
if (!GD)
continue;
+ if (!GD->isImplicit())
+ HasAnyDeductionGuide = true;
+
// C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
// For copy-initialization, the candidate functions are all the
// converting constructors (12.3.1) of that class.
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
- if (Kind.isCopyInit() && !ListInit) {
+ if (!AllowExplicit) {
// Only consider converting constructors.
if (GD->isExplicit())
continue;
@@ -9318,11 +9425,13 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
if (TD)
AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
- Inits, Candidates,
- SuppressUserConversions);
+ Inits, Candidates, SuppressUserConversions,
+ /*PartialOverloading*/ false,
+ AllowExplicit);
else
AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
- SuppressUserConversions);
+ SuppressUserConversions,
+ /*PartialOverloading*/ false, AllowExplicit);
}
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
};
@@ -9372,12 +9481,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
switch (Result) {
case OR_Ambiguous:
- Diag(Kind.getLocation(), diag::err_deduced_class_template_ctor_ambiguous)
- << TemplateName;
// FIXME: For list-initialization candidates, it'd usually be better to
// list why they were not viable when given the initializer list itself as
// an argument.
- Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(
+ Kind.getLocation(),
+ PDiag(diag::err_deduced_class_template_ctor_ambiguous)
+ << TemplateName),
+ *this, OCD_ViableCandidates, Inits);
return QualType();
case OR_No_Viable_Function: {
@@ -9385,11 +9497,13 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
cast<ClassTemplateDecl>(Template)->getTemplatedDecl();
bool Complete =
isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary));
- Diag(Kind.getLocation(),
- Complete ? diag::err_deduced_class_template_ctor_no_viable
- : diag::err_deduced_class_template_incomplete)
- << TemplateName << !Guides.empty();
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
+ Candidates.NoteCandidates(
+ PartialDiagnosticAt(
+ Kind.getLocation(),
+ PDiag(Complete ? diag::err_deduced_class_template_ctor_no_viable
+ : diag::err_deduced_class_template_incomplete)
+ << TemplateName << !Guides.empty()),
+ *this, OCD_AllCandidates, Inits);
return QualType();
}
@@ -9430,5 +9544,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_cxx14_compat_class_template_argument_deduction)
<< TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType;
+
+ // Warn if CTAD was used on a type that does not have any user-defined
+ // deduction guides.
+ if (!HasAnyDeductionGuide) {
+ Diag(TSInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_ctad_maybe_unsupported)
+ << TemplateName;
+ Diag(Template->getLocation(), diag::note_suppress_ctad_maybe_unsupported);
+ }
+
return DeducedType;
}
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index af233b96d69b..986524e6d56b 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -1,9 +1,8 @@
//===--- SemaLambda.cpp - Semantic Analysis for C++11 Lambdas -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -21,6 +20,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace sema;
@@ -226,19 +226,14 @@ Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
static inline TemplateParameterList *
getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
- if (LSI->GLTemplateParameterList)
- return LSI->GLTemplateParameterList;
-
- if (!LSI->AutoTemplateParams.empty()) {
- SourceRange IntroRange = LSI->IntroducerRange;
- SourceLocation LAngleLoc = IntroRange.getBegin();
- SourceLocation RAngleLoc = IntroRange.getEnd();
+ if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) {
LSI->GLTemplateParameterList = TemplateParameterList::Create(
SemaRef.Context,
- /*Template kw loc*/ SourceLocation(), LAngleLoc,
- llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
- LSI->AutoTemplateParams.size()),
- RAngleLoc, nullptr);
+ /*Template kw loc*/ SourceLocation(),
+ /*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(),
+ LSI->TemplateParams,
+ /*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(),
+ nullptr);
}
return LSI->GLTemplateParameterList;
}
@@ -372,12 +367,11 @@ Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
return *MangleNumbering;
}
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- const bool IsConstexprSpecified) {
+CXXMethodDecl *Sema::startLambdaDefinition(
+ CXXRecordDecl *Class, SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
+ Optional<std::pair<unsigned, Decl *>> Mangling) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -406,16 +400,12 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
= IntroducerRange.getBegin().getRawEncoding();
MethodNameLoc.CXXOperatorName.EndOpNameLoc
= IntroducerRange.getEnd().getRawEncoding();
- CXXMethodDecl *Method
- = CXXMethodDecl::Create(Context, Class, EndLoc,
- DeclarationNameInfo(MethodName,
- IntroducerRange.getBegin(),
- MethodNameLoc),
- MethodType, MethodTypeInfo,
- SC_None,
- /*isInline=*/true,
- IsConstexprSpecified,
- EndLoc);
+ CXXMethodDecl *Method = CXXMethodDecl::Create(
+ Context, Class, EndLoc,
+ DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
+ MethodNameLoc),
+ MethodType, MethodTypeInfo, SC_None,
+ /*isInline=*/true, ConstexprKind, EndLoc);
Method->setAccess(AS_public);
// Temporarily set the lexical declaration context to the current
@@ -443,12 +433,16 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
P->setOwningFunction(Method);
}
- Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(Class->getDeclContext(),
- ManglingContextDecl)) {
- unsigned ManglingNumber = MCtx->getManglingNumber(Method);
- Class->setLambdaMangling(ManglingNumber, ManglingContextDecl);
+ if (Mangling) {
+ Class->setLambdaMangling(Mangling->first, Mangling->second);
+ } else {
+ Decl *ManglingContextDecl;
+ if (MangleNumberingContext *MCtx =
+ getCurrentMangleNumberContext(Class->getDeclContext(),
+ ManglingContextDecl)) {
+ unsigned ManglingNumber = MCtx->getManglingNumber(Method);
+ Class->setLambdaMangling(ManglingNumber, ManglingContextDecl);
+ }
}
return Method;
@@ -493,6 +487,23 @@ void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
LSI->finishedExplicitCaptures();
}
+void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+ ArrayRef<NamedDecl *> TParams,
+ SourceLocation RAngleLoc) {
+ LambdaScopeInfo *LSI = getCurLambda();
+ assert(LSI && "Expected a lambda scope");
+ assert(LSI->NumExplicitTemplateParams == 0 &&
+ "Already acted on explicit template parameters");
+ assert(LSI->TemplateParams.empty() &&
+ "Explicit template parameters should come "
+ "before invented (auto) ones");
+ assert(!TParams.empty() &&
+ "No template parameters to act on");
+ LSI->TemplateParams.append(TParams.begin(), TParams.end());
+ LSI->NumExplicitTemplateParams = TParams.size();
+ LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
+}
+
void Sema::addLambdaParameters(
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
CXXMethodDecl *CallOperator, Scope *CurScope) {
@@ -741,11 +752,10 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
}
}
-QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
- bool ByRef,
- IdentifierInfo *Id,
- bool IsDirectInit,
- Expr *&Init) {
+QualType Sema::buildLambdaInitCaptureInitialization(
+ SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
+ Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit,
+ Expr *&Init) {
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
// deduce against.
QualType DeductType = Context.getAutoDeductType();
@@ -756,18 +766,29 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
assert(!DeductType.isNull() && "can't build reference to auto");
TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc);
}
+ if (EllipsisLoc.isValid()) {
+ if (Init->containsUnexpandedParameterPack()) {
+ Diag(EllipsisLoc, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_init_capture_pack
+ : diag::ext_init_capture_pack);
+ DeductType = Context.getPackExpansionType(DeductType, NumExpansions);
+ TLB.push<PackExpansionTypeLoc>(DeductType).setEllipsisLoc(EllipsisLoc);
+ } else {
+ // Just ignore the ellipsis for now and form a non-pack variable. We'll
+ // diagnose this later when we try to capture it.
+ }
+ }
TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
// Deduce the type of the init capture.
- Expr *DeduceInit = Init;
QualType DeducedType = deduceVarTypeFromInitializer(
/*VarDecl*/nullptr, DeclarationName(Id), DeductType, TSI,
- SourceRange(Loc, Loc), IsDirectInit, DeduceInit);
+ SourceRange(Loc, Loc), IsDirectInit, Init);
if (DeducedType.isNull())
return QualType();
// Are we a non-list direct initialization?
- bool CXXDirectInit = isa<ParenListExpr>(Init);
+ ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
// Perform initialization analysis and ensure any implicit conversions
// (such as lvalue-to-rvalue) are enforced.
@@ -780,7 +801,10 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
: InitializationKind::CreateDirectList(Loc))
: InitializationKind::CreateCopy(Loc, Init->getBeginLoc());
- MultiExprArg Args = DeduceInit;
+ MultiExprArg Args = Init;
+ if (CXXDirectInit)
+ Args =
+ MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs());
QualType DclT;
InitializationSequence InitSeq(*this, Entity, Kind, Args);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
@@ -794,10 +818,15 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
QualType InitCaptureType,
+ SourceLocation EllipsisLoc,
IdentifierInfo *Id,
unsigned InitStyle, Expr *Init) {
- TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
- Loc);
+ // FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization
+ // rather than reconstructing it here.
+ TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc);
+ if (auto PETL = TSI->getTypeLoc().getAs<PackExpansionTypeLoc>())
+ PETL.setEllipsisLoc(EllipsisLoc);
+
// Create a dummy variable representing the init-capture. This is not actually
// used as a variable, and only exists as a way to name and refer to the
// init-capture.
@@ -813,35 +842,33 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
return NewVD;
}
-FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
- FieldDecl *Field = FieldDecl::Create(
- Context, LSI->Lambda, Var->getLocation(), Var->getLocation(),
- nullptr, Var->getType(), Var->getTypeSourceInfo(), nullptr, false,
- ICIS_NoInit);
- Field->setImplicit(true);
- Field->setAccess(AS_private);
- LSI->Lambda->addDecl(Field);
-
+void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
+ assert(Var->isInitCapture() && "init capture flag should be set");
LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
/*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), Var->getInit());
- return Field;
+ Var->getType(), /*Invalid*/false);
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
- // Determine if we're within a context where we know that the lambda will
- // be dependent, because there are template parameters in scope.
- bool KnownDependent = false;
LambdaScopeInfo *const LSI = getCurLambda();
assert(LSI && "LambdaScopeInfo should be on stack!");
- // 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 if we're within a context where we know that the lambda will
+ // be dependent, because there are template parameters in scope.
+ bool KnownDependent;
+ if (LSI->NumExplicitTemplateParams > 0) {
+ auto *TemplateParamScope = CurScope->getTemplateParamParent();
+ assert(TemplateParamScope &&
+ "Lambda with explicit template param list should establish a "
+ "template param scope");
+ assert(TemplateParamScope->getParent());
+ KnownDependent = TemplateParamScope->getParent()
+ ->getTemplateParamParent() != nullptr;
+ } else {
+ KnownDependent = CurScope->getTemplateParamParent() != nullptr;
+ }
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
@@ -909,7 +936,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
- ParamInfo.getDeclSpec().isConstexprSpecified());
+ ParamInfo.getDeclSpec().getConstexprSpecifier());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1016,8 +1043,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
? diag::warn_cxx11_compat_init_capture
: diag::ext_init_capture);
- if (C->Init.get()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
// If the initializer expression is usable, but the InitCaptureType
// is not, then an error has occurred - so ignore the capture for now.
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
@@ -1026,6 +1051,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->InitCaptureType.get().isNull())
continue;
+ if (C->Init.get()->containsUnexpandedParameterPack() &&
+ !C->InitCaptureType.get()->getAs<PackExpansionType>())
+ ContainsUnexpandedParameterPack = true;
+
unsigned InitStyle;
switch (C->InitKind) {
case LambdaCaptureInitKind::NoInit:
@@ -1041,7 +1070,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
break;
}
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
- C->Id, InitStyle, C->Init.get());
+ C->EllipsisLoc, C->Id, InitStyle,
+ C->Init.get());
// C++1y [expr.prim.lambda]p11:
// An init-capture behaves as if it declares and explicitly
// captures a variable [...] whose declarative region is the
@@ -1080,8 +1110,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (R.empty()) {
// FIXME: Disable corrections that would add qualification?
CXXScopeSpec ScopeSpec;
- if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R,
- llvm::make_unique<DeclFilterCCC<VarDecl>>()))
+ DeclFilterCCC<VarDecl> Validator{};
+ if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator))
continue;
}
@@ -1133,7 +1163,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
EllipsisLoc = C->EllipsisLoc;
} else {
Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
- << SourceRange(C->Loc);
+ << (C->Init.isUsable() ? C->Init.get()->getSourceRange()
+ : SourceRange(C->Loc));
// Just ignore the ellipsis.
}
@@ -1142,7 +1173,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
if (C->Init.isUsable()) {
- buildInitCaptureField(LSI, Var);
+ addInitCapture(LSI, Var);
} else {
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
@@ -1228,9 +1259,10 @@ static void addFunctionPointerConversion(Sema &S,
FunctionProtoType::ExtProtoInfo ConvExtInfo(
S.Context.getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
- // The conversion function is always const.
+ // The conversion function is always const and noexcept.
ConvExtInfo.TypeQuals = Qualifiers();
ConvExtInfo.TypeQuals.addConst();
+ ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept;
QualType ConvTy =
S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
@@ -1296,7 +1328,7 @@ static void addFunctionPointerConversion(Sema &S,
S.Context.getTranslationUnitDecl(), From->getBeginLoc(),
From->getLocation(), From->getIdentifier(), From->getType(),
From->getTypeSourceInfo(), From->getStorageClass(),
- /*DefaultArg=*/nullptr));
+ /*DefArg=*/nullptr));
CallOpConvTL.setParam(I, From);
CallOpConvNameTL.setParam(I, From);
}
@@ -1304,8 +1336,8 @@ static void addFunctionPointerConversion(Sema &S,
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
S.Context, Class, Loc,
DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
- /*isInline=*/true, /*isExplicit=*/false,
- /*isConstexpr=*/S.getLangOpts().CPlusPlus17,
+ /*isInline=*/true, ExplicitSpecifier(),
+ S.getLangOpts().CPlusPlus17 ? CSK_constexpr : CSK_unspecified,
CallOperator->getBody()->getEndLoc());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
@@ -1344,8 +1376,7 @@ static void addFunctionPointerConversion(Sema &S,
CXXMethodDecl *Invoke = CXXMethodDecl::Create(
S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
- /*IsInline=*/true,
- /*IsConstexpr=*/false, CallOperator->getBody()->getEndLoc());
+ /*isInline=*/true, CSK_unspecified, CallOperator->getBody()->getEndLoc());
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
InvokerParams[I]->setOwningFunction(Invoke);
Invoke->setParams(InvokerParams);
@@ -1391,21 +1422,29 @@ static void addBlockPointerConversion(Sema &S,
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
- /*isInline=*/true, /*isExplicit=*/false,
- /*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
+ /*isInline=*/true, ExplicitSpecifier(), CSK_unspecified,
+ CallOperator->getBody()->getEndLoc());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Class->addDecl(Conversion);
}
-static ExprResult performLambdaVarCaptureInitialization(
- Sema &S, const Capture &Capture, FieldDecl *Field,
- SourceLocation ImplicitCaptureLoc, bool IsImplicitCapture) {
- assert(Capture.isVariableCapture() && "not a variable capture");
+ExprResult Sema::BuildCaptureInit(const Capture &Cap,
+ SourceLocation ImplicitCaptureLoc,
+ bool IsOpenMPMapping) {
+ // VLA captures don't have a stored initialization expression.
+ if (Cap.isVLATypeCapture())
+ return ExprResult();
+
+ // An init-capture is initialized directly from its stored initializer.
+ if (Cap.isInitCapture())
+ return Cap.getVariable()->getInit();
- auto *Var = Capture.getVariable();
+ // For anything else, build an initialization expression. For an implicit
+ // capture, the capture notionally happens at the capture-default, so use
+ // that location here.
SourceLocation Loc =
- IsImplicitCapture ? ImplicitCaptureLoc : Capture.getLocation();
+ ImplicitCaptureLoc.isValid() ? ImplicitCaptureLoc : Cap.getLocation();
// C++11 [expr.prim.lambda]p21:
// When the lambda-expression is evaluated, the entities that
@@ -1419,17 +1458,39 @@ static ExprResult performLambdaVarCaptureInitialization(
// C++ [expr.prim.lambda]p12:
// An entity captured by a lambda-expression is odr-used (3.2) in
// the scope containing the lambda-expression.
- ExprResult RefResult = S.BuildDeclarationNameExpr(
+ ExprResult Init;
+ IdentifierInfo *Name = nullptr;
+ if (Cap.isThisCapture()) {
+ QualType ThisTy = getCurrentThisType();
+ Expr *This = BuildCXXThisExpr(Loc, ThisTy, ImplicitCaptureLoc.isValid());
+ if (Cap.isCopyCapture())
+ Init = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+ else
+ Init = This;
+ } else {
+ assert(Cap.isVariableCapture() && "unknown kind of capture");
+ VarDecl *Var = Cap.getVariable();
+ Name = Var->getIdentifier();
+ Init = BuildDeclarationNameExpr(
CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
- if (RefResult.isInvalid())
+ }
+
+ // In OpenMP, the capture kind doesn't actually describe how to capture:
+ // variables are "mapped" onto the device in a process that does not formally
+ // make a copy, even for a "copy capture".
+ if (IsOpenMPMapping)
+ return Init;
+
+ if (Init.isInvalid())
return ExprError();
- Expr *Ref = RefResult.get();
- auto Entity = InitializedEntity::InitializeLambdaCapture(
- Var->getIdentifier(), Field->getType(), Loc);
- InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(S, Entity, InitKind, Ref);
- return Init.Perform(S, Entity, InitKind, Ref);
+ Expr *InitExpr = Init.get();
+ InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture(
+ Name, Cap.getCaptureType(), Loc);
+ InitializationKind InitKind =
+ InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationSequence InitSeq(*this, Entity, InitKind, InitExpr);
+ return InitSeq.Perform(*this, Entity, InitKind, InitExpr);
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
@@ -1456,8 +1517,8 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
}
bool Sema::CaptureHasSideEffects(const Capture &From) {
- if (!From.isVLATypeCapture()) {
- Expr *Init = From.getInitExpr();
+ if (From.isInitCapture()) {
+ Expr *Init = From.getVariable()->getInit();
if (Init && Init->HasSideEffects(Context))
return true;
}
@@ -1498,6 +1559,54 @@ bool Sema::DiagnoseUnusedLambdaCapture(SourceRange CaptureRange,
return true;
}
+/// Create a field within the lambda class or captured statement record for the
+/// given capture.
+FieldDecl *Sema::BuildCaptureField(RecordDecl *RD,
+ const sema::Capture &Capture) {
+ SourceLocation Loc = Capture.getLocation();
+ QualType FieldType = Capture.getCaptureType();
+
+ TypeSourceInfo *TSI = nullptr;
+ if (Capture.isVariableCapture()) {
+ auto *Var = Capture.getVariable();
+ if (Var->isInitCapture())
+ TSI = Capture.getVariable()->getTypeSourceInfo();
+ }
+
+ // FIXME: Should we really be doing this? A null TypeSourceInfo seems more
+ // appropriate, at least for an implicit capture.
+ if (!TSI)
+ TSI = Context.getTrivialTypeSourceInfo(FieldType, Loc);
+
+ // Build the non-static data member.
+ FieldDecl *Field =
+ FieldDecl::Create(Context, RD, Loc, Loc, nullptr, FieldType, TSI, nullptr,
+ false, ICIS_NoInit);
+ // If the variable being captured has an invalid type, mark the class as
+ // invalid as well.
+ if (!FieldType->isDependentType()) {
+ if (RequireCompleteType(Loc, FieldType, diag::err_field_incomplete)) {
+ RD->setInvalidDecl();
+ Field->setInvalidDecl();
+ } else {
+ NamedDecl *Def;
+ FieldType->isIncompleteType(&Def);
+ if (Def && Def->isInvalidDecl()) {
+ RD->setInvalidDecl();
+ Field->setInvalidDecl();
+ }
+ }
+ }
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ RD->addDecl(Field);
+
+ if (Capture.isVLATypeCapture())
+ Field->setCapturedVLAType(Capture.getCapturedVLAType());
+
+ return Field;
+}
+
ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaScopeInfo *LSI) {
// Collect information from the lambda scope.
@@ -1535,28 +1644,33 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
PopExpressionEvaluationContext();
- // Translate captures.
- auto CurField = Class->field_begin();
// True if the current capture has a used capture or default before it.
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
SourceLocation PrevCaptureLoc = CurHasPreviousCapture ?
CaptureDefaultLoc : IntroducerRange.getBegin();
- for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) {
+ for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
const Capture &From = LSI->Captures[I];
+ if (From.isInvalid())
+ return ExprError();
+
assert(!From.isBlockCapture() && "Cannot capture __block variables");
bool IsImplicit = I >= LSI->NumExplicitCaptures;
+ SourceLocation ImplicitCaptureLoc =
+ IsImplicit ? CaptureDefaultLoc : SourceLocation();
// Use source ranges of explicit captures for fixits where available.
SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I];
// Warn about unused explicit captures.
bool IsCaptureUsed = true;
- if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+ if (!CurContext->isDependentContext() && !IsImplicit &&
+ !From.isODRUsed()) {
// Initialized captures that are non-ODR used may not be eliminated.
+ // FIXME: Where did the IsGenericLambda here come from?
bool NonODRUsedInitCapture =
- IsGenericLambda && From.isNonODRUsed() && From.getInitExpr();
+ IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
if (!NonODRUsedInitCapture) {
bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
SourceRange FixItRange;
@@ -1582,45 +1696,44 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
PrevCaptureLoc = CaptureRange.getEnd();
}
- // Handle 'this' capture.
- if (From.isThisCapture()) {
- // Capturing 'this' implicitly with a default of '[=]' is deprecated,
- // because it results in a reference capture. Don't warn prior to
- // C++2a; there's nothing that can be done about it before then.
- if (getLangOpts().CPlusPlus2a && IsImplicit &&
- CaptureDefault == LCD_ByCopy) {
- Diag(From.getLocation(), diag::warn_deprecated_this_capture);
- Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
- << FixItHint::CreateInsertion(
- getLocForEndOfToken(CaptureDefaultLoc), ", this");
+ // Map the capture to our AST representation.
+ LambdaCapture Capture = [&] {
+ if (From.isThisCapture()) {
+ // Capturing 'this' implicitly with a default of '[=]' is deprecated,
+ // because it results in a reference capture. Don't warn prior to
+ // C++2a; there's nothing that can be done about it before then.
+ if (getLangOpts().CPlusPlus2a && IsImplicit &&
+ CaptureDefault == LCD_ByCopy) {
+ Diag(From.getLocation(), diag::warn_deprecated_this_capture);
+ Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
+ << FixItHint::CreateInsertion(
+ getLocForEndOfToken(CaptureDefaultLoc), ", this");
+ }
+ return LambdaCapture(From.getLocation(), IsImplicit,
+ From.isCopyCapture() ? LCK_StarThis : LCK_This);
+ } else if (From.isVLATypeCapture()) {
+ return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
+ } else {
+ assert(From.isVariableCapture() && "unknown kind of capture");
+ VarDecl *Var = From.getVariable();
+ LambdaCaptureKind Kind =
+ From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
+ return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
+ From.getEllipsisLoc());
}
+ }();
- Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit,
- From.isCopyCapture() ? LCK_StarThis : LCK_This));
- CaptureInits.push_back(From.getInitExpr());
- continue;
- }
- if (From.isVLATypeCapture()) {
- Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
- CaptureInits.push_back(nullptr);
- continue;
- }
+ // Form the initializer for the capture field.
+ ExprResult Init = BuildCaptureInit(From, ImplicitCaptureLoc);
- VarDecl *Var = From.getVariable();
- LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
- Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind,
- Var, From.getEllipsisLoc()));
- Expr *Init = From.getInitExpr();
- if (!Init) {
- auto InitResult = performLambdaVarCaptureInitialization(
- *this, From, *CurField, CaptureDefaultLoc, IsImplicit);
- if (InitResult.isInvalid())
- return ExprError();
- Init = InitResult.get();
- }
- CaptureInits.push_back(Init);
+ // FIXME: Skip this capture if the capture is not used, the initializer
+ // has no side-effects, the type of the capture is trivial, and the
+ // lambda is not externally visible.
+
+ // Add a FieldDecl for the capture and form its initializer.
+ BuildCaptureField(Class, From);
+ Captures.push_back(Capture);
+ CaptureInits.push_back(Init.get());
}
// C++11 [expr.prim.lambda]p6:
@@ -1664,9 +1777,11 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
TentativeAnalysisScope DiagnosticScopeGuard(*this);
- CallOperator->setConstexpr(
- CheckConstexprFunctionDecl(CallOperator) &&
- CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()));
+ CallOperator->setConstexprKind(
+ (CheckConstexprFunctionDecl(CallOperator) &&
+ CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()))
+ ? CSK_constexpr
+ : CSK_unspecified);
}
// Emit delayed shadowing warnings now that the full capture list is known.
@@ -1745,7 +1860,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
Context, Block, From->getBeginLoc(), From->getLocation(),
From->getIdentifier(), From->getType(), From->getTypeSourceInfo(),
From->getStorageClass(),
- /*DefaultArg=*/nullptr));
+ /*DefArg=*/nullptr));
}
Block->setParams(BlockParams);
@@ -1760,8 +1875,8 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
ConvLocation, nullptr,
Src->getType(), CapVarTSI,
SC_None);
- BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
- /*Nested=*/false, /*Copy=*/Init.get());
+ BlockDecl::Capture Capture(/*variable=*/CapVar, /*byRef=*/false,
+ /*nested=*/false, /*copy=*/Init.get());
Block->setCaptures(Context, Capture, /*CapturesCXXThis=*/false);
// Add a fake function body to the block. IR generation is responsible
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index effccc2f3d38..8a24dd884a76 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -1,9 +1,8 @@
//===--------------------- SemaLookup.cpp - Name Lookup ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -22,6 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleLoader.h"
@@ -47,6 +47,8 @@
#include <utility>
#include <vector>
+#include "OpenCLBuiltins.inc"
+
using namespace clang;
using namespace sema;
@@ -279,6 +281,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_OMPReduction;
break;
+ case Sema::LookupOMPMapperName:
+ IDNS = Decl::IDNS_OMPMapper;
+ break;
+
case Sema::LookupAnyName:
IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
| Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol
@@ -667,6 +673,79 @@ LLVM_DUMP_METHOD void LookupResult::dump() {
D->dump();
}
+/// When trying to resolve a function name, if the isOpenCLBuiltin function
+/// defined in "OpenCLBuiltins.inc" returns a non-null <Index, Len>, then the
+/// identifier is referencing an OpenCL builtin function. Thus, all its
+/// prototypes are added to the LookUpResult.
+///
+/// \param S The Sema instance
+/// \param LR The LookupResult instance
+/// \param II The identifier being resolved
+/// \param Index The list of prototypes starts at Index in OpenCLBuiltins[]
+/// \param Len The list of prototypes has Len elements
+static void InsertOCLBuiltinDeclarations(Sema &S, LookupResult &LR,
+ IdentifierInfo *II, unsigned Index,
+ unsigned Len) {
+
+ for (unsigned i = 0; i < Len; ++i) {
+ const OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i];
+ ASTContext &Context = S.Context;
+
+ // Ignore this BIF if the version is incorrect.
+ if (Context.getLangOpts().OpenCLVersion < Decl.Version)
+ continue;
+
+ FunctionProtoType::ExtProtoInfo PI;
+ PI.Variadic = false;
+
+ // Defined in "OpenCLBuiltins.inc"
+ QualType RT = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex]);
+
+ SmallVector<QualType, 5> ArgTypes;
+ for (unsigned I = 1; I < Decl.NumArgs; I++) {
+ QualType Ty = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex + I]);
+ ArgTypes.push_back(Ty);
+ }
+
+ QualType R = Context.getFunctionType(RT, ArgTypes, PI);
+ SourceLocation Loc = LR.getNameLoc();
+
+ // TODO: This part is taken from Sema::LazilyCreateBuiltin,
+ // maybe refactor it.
+ DeclContext *Parent = Context.getTranslationUnitDecl();
+ FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R,
+ /*TInfo=*/nullptr, SC_Extern,
+ false, R->isFunctionProtoType());
+ New->setImplicit();
+
+ // Create Decl objects for each parameter, adding them to the
+ // FunctionDecl.
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
+ SmallVector<ParmVarDecl *, 16> Params;
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
+ ParmVarDecl *Parm =
+ ParmVarDecl::Create(Context, New, SourceLocation(),
+ SourceLocation(), nullptr, FT->getParamType(i),
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Parm->setScopeInfo(0, i);
+ Params.push_back(Parm);
+ }
+ New->setParams(Params);
+ }
+
+ New->addAttr(OverloadableAttr::CreateImplicit(Context));
+
+ if (strlen(Decl.Extension))
+ S.setOpenCLExtensionForDecl(New, Decl.Extension);
+
+ LR.addDecl(New);
+ }
+
+ // If we added overloads, need to resolve the lookup result.
+ if (Len > 1)
+ LR.resolveKind();
+}
+
/// Lookup a builtin function, when name lookup would otherwise
/// fail.
static bool LookupBuiltin(Sema &S, LookupResult &R) {
@@ -689,6 +768,15 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
}
}
+ // Check if this is an OpenCL Builtin, and if so, insert its overloads.
+ if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) {
+ auto Index = isOpenCLBuiltin(II->getName());
+ if (Index.first) {
+ InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second);
+ return true;
+ }
+ }
+
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
@@ -1540,8 +1628,21 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
// and in C we must not because each declaration of a function gets its own
// set of declarations for tags in prototype scope.
bool VisibleWithinParent;
- if (D->isTemplateParameter() || isa<ParmVarDecl>(D) ||
- (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
+ if (D->isTemplateParameter()) {
+ bool SearchDefinitions = true;
+ if (const auto *DCD = dyn_cast<Decl>(DC)) {
+ if (const auto *TD = DCD->getDescribedTemplate()) {
+ TemplateParameterList *TPL = TD->getTemplateParameters();
+ auto Index = getDepthAndIndex(D).second;
+ SearchDefinitions = Index >= TPL->size() || TPL->getParam(Index) != D;
+ }
+ }
+ if (SearchDefinitions)
+ VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC));
+ else
+ VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC));
+ } else if (isa<ParmVarDecl>(D) ||
+ (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC));
else if (D->isModulePrivate()) {
// A module-private declaration is only visible if an enclosing lexical
@@ -2104,6 +2205,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
BaseCallback = &CXXRecordDecl::FindOMPReductionMember;
break;
+ case LookupOMPMapperName:
+ BaseCallback = &CXXRecordDecl::FindOMPMapperMember;
+ break;
+
case LookupUsingDeclName:
// This lookup is for redeclarations only.
@@ -2165,11 +2270,27 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin();
DeclContext::lookup_iterator CurrentD = Path->Decls.begin();
+ // Get the decl that we should use for deduplicating this lookup.
+ auto GetRepresentativeDecl = [&](NamedDecl *D) -> Decl * {
+ // C++ [temp.local]p3:
+ // A lookup that finds an injected-class-name (10.2) can result in
+ // an ambiguity in certain cases (for example, if it is found in
+ // more than one base class). If all of the injected-class-names
+ // that are found refer to specializations of the same class
+ // template, and if the name is used as a template-name, the
+ // reference refers to the class template itself and not a
+ // specialization thereof, and is not ambiguous.
+ if (R.isTemplateNameLookup())
+ if (auto *TD = getAsTemplateNameDecl(D))
+ D = TD;
+ return D->getUnderlyingDecl()->getCanonicalDecl();
+ };
+
while (FirstD != FirstPath->Decls.end() &&
CurrentD != Path->Decls.end()) {
- if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() !=
- (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl())
- break;
+ if (GetRepresentativeDecl(*FirstD) !=
+ GetRepresentativeDecl(*CurrentD))
+ break;
++FirstD;
++CurrentD;
@@ -2417,40 +2538,56 @@ namespace {
InstantiationLoc(InstantiationLoc) {
}
+ bool addClassTransitive(CXXRecordDecl *RD) {
+ Classes.insert(RD);
+ return ClassesTransitive.insert(RD);
+ }
+
Sema &S;
Sema::AssociatedNamespaceSet &Namespaces;
Sema::AssociatedClassSet &Classes;
SourceLocation InstantiationLoc;
+
+ private:
+ Sema::AssociatedClassSet ClassesTransitive;
};
} // end anonymous namespace
static void
addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType T);
+// Given the declaration context \param Ctx of a class, class template or
+// enumeration, add the associated namespaces to \param Namespaces as described
+// in [basic.lookup.argdep]p2.
static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces,
DeclContext *Ctx) {
- // Add the associated namespace for this class.
-
- // We don't use DeclContext::getEnclosingNamespaceContext() as this may
- // be a locally scoped record.
+ // The exact wording has been changed in C++14 as a result of
+ // CWG 1691 (see also CWG 1690 and CWG 1692). We apply it unconditionally
+ // to all language versions since it is possible to return a local type
+ // from a lambda in C++11.
+ //
+ // C++14 [basic.lookup.argdep]p2:
+ // If T is a class type [...]. Its associated namespaces are the innermost
+ // enclosing namespaces of its associated classes. [...]
+ //
+ // If T is an enumeration type, its associated namespace is the innermost
+ // enclosing namespace of its declaration. [...]
- // We skip out of inline namespaces. The innermost non-inline namespace
+ // We additionally skip inline namespaces. The innermost non-inline namespace
// contains all names of all its nested inline namespaces anyway, so we can
// replace the entire inline namespace tree with its root.
- while (Ctx->isRecord() || Ctx->isTransparentContext() ||
- Ctx->isInlineNamespace())
+ while (!Ctx->isFileContext() || Ctx->isInlineNamespace())
Ctx = Ctx->getParent();
- if (Ctx->isFileContext())
- Namespaces.insert(Ctx->getPrimaryContext());
+ Namespaces.insert(Ctx->getPrimaryContext());
}
// Add the associated classes and namespaces for argument-dependent
-// lookup that involves a template argument (C++ [basic.lookup.koenig]p2).
+// lookup that involves a template argument (C++ [basic.lookup.argdep]p2).
static void
addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
const TemplateArgument &Arg) {
- // C++ [basic.lookup.koenig]p2, last bullet:
+ // C++ [basic.lookup.argdep]p2, last bullet:
// -- [...] ;
switch (Arg.getKind()) {
case TemplateArgument::Null:
@@ -2495,9 +2632,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
}
}
-// Add the associated classes and namespaces for
-// argument-dependent lookup with an argument of class type
-// (C++ [basic.lookup.koenig]p2).
+// Add the associated classes and namespaces for argument-dependent lookup
+// with an argument of class type (C++ [basic.lookup.argdep]p2).
static void
addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
CXXRecordDecl *Class) {
@@ -2506,30 +2642,22 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
if (Class->getDeclName() == Result.S.VAListTagName)
return;
- // C++ [basic.lookup.koenig]p2:
+ // C++ [basic.lookup.argdep]p2:
// [...]
// -- If T is a class type (including unions), its associated
// classes are: the class itself; the class of which it is a
- // member, if any; and its direct and indirect base
- // classes. Its associated namespaces are the namespaces in
- // which its associated classes are defined.
+ // member, if any; and its direct and indirect base classes.
+ // Its associated namespaces are the innermost enclosing
+ // namespaces of its associated classes.
// Add the class of which it is a member, if any.
DeclContext *Ctx = Class->getDeclContext();
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
Result.Classes.insert(EnclosingClass);
+
// Add the associated namespace for this class.
CollectEnclosingNamespace(Result.Namespaces, Ctx);
- // Add the class itself. If we've already seen this class, we don't
- // need to visit base classes.
- //
- // 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))
- return;
-
// -- If T is a template-id, its associated namespaces and classes are
// the namespace in which the template is defined; for member
// templates, the member template's class; the namespaces and classes
@@ -2552,6 +2680,11 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
addAssociatedClassesAndNamespaces(Result, TemplateArgs[I]);
}
+ // Add the class itself. If we've already transitively visited this class,
+ // we don't need to visit base classes.
+ if (!Result.addClassTransitive(Class))
+ return;
+
// Only recurse into base classes for complete types.
if (!Result.S.isCompleteType(Result.InstantiationLoc,
Result.S.Context.getRecordType(Class)))
@@ -2577,7 +2710,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
if (!BaseType)
continue;
CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (Result.Classes.insert(BaseDecl)) {
+ if (Result.addClassTransitive(BaseDecl)) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
CollectEnclosingNamespace(Result.Namespaces, BaseCtx);
@@ -2642,10 +2775,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
break;
// -- If T is a class type (including unions), its associated
- // classes are: the class itself; the class of which it is a
- // member, if any; and its direct and indirect base
- // classes. Its associated namespaces are the namespaces in
- // which its associated classes are defined.
+ // classes are: the class itself; the class of which it is
+ // a member, if any; and its direct and indirect base classes.
+ // Its associated namespaces are the innermost enclosing
+ // namespaces of its associated classes.
case Type::Record: {
CXXRecordDecl *Class =
cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
@@ -2653,10 +2786,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
break;
}
- // -- If T is an enumeration type, its associated namespace is
- // the namespace in which it is defined. If it is class
- // member, its associated class is the member's class; else
- // it has no associated class.
+ // -- If T is an enumeration type, its associated namespace
+ // is the innermost enclosing namespace of its declaration.
+ // If it is a class member, its associated class is the
+ // member’s class; else it has no associated class.
case Type::Enum: {
EnumDecl *Enum = cast<EnumType>(T)->getDecl();
@@ -2664,7 +2797,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
Result.Classes.insert(EnclosingClass);
- // Add the associated namespace for this class.
+ // Add the associated namespace for this enumeration.
CollectEnclosingNamespace(Result.Namespaces, Ctx);
break;
@@ -2793,15 +2926,9 @@ void Sema::FindAssociatedClassesAndNamespaces(
// in which the function or function template is defined and the
// classes and namespaces associated with its (non-dependent)
// parameter types and return type.
- Arg = Arg->IgnoreParens();
- if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg))
- if (unaryOp->getOpcode() == UO_AddrOf)
- Arg = unaryOp->getSubExpr();
+ OverloadExpr *OE = OverloadExpr::find(Arg).Expression;
- UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg);
- if (!ULE) continue;
-
- for (const auto *D : ULE->decls()) {
+ for (const NamedDecl *D : OE->decls()) {
// Look through any using declarations to find the underlying function.
const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction();
@@ -2999,10 +3126,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ /*SuppressUserConversions*/ true);
else
AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
- true);
+ /*SuppressUserConversions*/ true);
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
@@ -4317,9 +4445,8 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier(
SpecifierOStream.flush();
SameNameSpecifier = NewNameSpecifier == CurNameSpecifier;
}
- if (SameNameSpecifier ||
- std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
- Name) != CurContextIdentifiers.end()) {
+ if (SameNameSpecifier || llvm::find(CurContextIdentifiers, Name) !=
+ CurContextIdentifiers.end()) {
// Rebuild the NestedNameSpecifier as a globally-qualified specifier.
NNS = NestedNameSpecifier::GlobalSpecifier(Context);
NumSpecifiers =
@@ -4551,8 +4678,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind,
- Scope *S, CXXScopeSpec *SS,
- std::unique_ptr<CorrectionCandidateCallback> CCC,
+ Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC,
DeclContext *MemberContext, bool EnteringContext,
const ObjCObjectPointerType *OPT, bool ErrorRecovery) {
@@ -4614,9 +4740,13 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
TypoName.getBeginLoc());
}
- CorrectionCandidateCallback &CCCRef = *CCC;
+ // Extend the lifetime of the callback. We delayed this until here
+ // to avoid allocations in the hot path (which is where no typo correction
+ // occurs). Note that CorrectionCandidateCallback is polymorphic and
+ // initially stack-allocated.
+ std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone();
auto Consumer = llvm::make_unique<TypoCorrectionConsumer>(
- *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
+ *this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext,
EnteringContext);
// Perform name lookup to find visible, similarly-named entities.
@@ -4668,7 +4798,9 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
}
}
- AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty());
+ AddKeywordsToConsumer(*this, *Consumer, S,
+ *Consumer->getCorrectionValidator(),
+ SS && SS->isNotEmpty());
// Build the NestedNameSpecifiers for the KnownNamespaces, if we're going
// to search those namespaces.
@@ -4722,19 +4854,18 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
- std::unique_ptr<CorrectionCandidateCallback> CCC,
+ CorrectionCandidateCallback &CCC,
CorrectTypoKind Mode,
DeclContext *MemberContext,
bool EnteringContext,
const ObjCObjectPointerType *OPT,
bool RecordFailure) {
- assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback");
-
// Always let the ExternalSource have the first chance at correction, even
// if we would otherwise have given up.
if (ExternalSource) {
- if (TypoCorrection Correction = ExternalSource->CorrectTypo(
- TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT))
+ if (TypoCorrection Correction =
+ ExternalSource->CorrectTypo(TypoName, LookupKind, S, SS, CCC,
+ MemberContext, EnteringContext, OPT))
return Correction;
}
@@ -4742,12 +4873,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
// some instances of CTC_Unknown, while WantRemainingKeywords is true
// for CTC_Unknown but not for CTC_ObjCMessageReceiver.
- bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords;
+ bool ObjCMessageReceiver = CCC.WantObjCSuper && !CCC.WantRemainingKeywords;
IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
- auto Consumer = makeTypoCorrectionConsumer(
- TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
- EnteringContext, OPT, Mode == CTK_ErrorRecovery);
+ auto Consumer = makeTypoCorrectionConsumer(TypoName, LookupKind, S, SS, CCC,
+ MemberContext, EnteringContext,
+ OPT, Mode == CTK_ErrorRecovery);
if (!Consumer)
return TypoCorrection();
@@ -4857,16 +4988,13 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
/// needed.
TypoExpr *Sema::CorrectTypoDelayed(
const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind,
- Scope *S, CXXScopeSpec *SS,
- std::unique_ptr<CorrectionCandidateCallback> CCC,
+ Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC,
TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode,
DeclContext *MemberContext, bool EnteringContext,
const ObjCObjectPointerType *OPT) {
- assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback");
-
- auto Consumer = makeTypoCorrectionConsumer(
- TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
- EnteringContext, OPT, Mode == CTK_ErrorRecovery);
+ auto Consumer = makeTypoCorrectionConsumer(TypoName, LookupKind, S, SS, CCC,
+ MemberContext, EnteringContext,
+ OPT, Mode == CTK_ErrorRecovery);
// Give the external sema source a chance to correct the typo.
TypoCorrection ExternalTypo;
@@ -4954,7 +5082,9 @@ FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
: NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs),
CurContext(SemaRef.CurContext), MemberFn(ME) {
WantTypeSpecifiers = false;
- WantFunctionLikeCasts = SemaRef.getLangOpts().CPlusPlus && NumArgs == 1;
+ WantFunctionLikeCasts = SemaRef.getLangOpts().CPlusPlus &&
+ !HasExplicitTemplateArgs && NumArgs == 1;
+ WantCXXNamedCasts = HasExplicitTemplateArgs && NumArgs == 1;
WantRemainingKeywords = false;
}
@@ -4983,6 +5113,13 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) {
}
}
+ // A typo for a function-style cast can look like a function call in C++.
+ if ((HasExplicitTemplateArgs ? getAsTypeTemplateDecl(ND) != nullptr
+ : isa<TypeDecl>(ND)) &&
+ CurContext->getParentASTContext().getLangOpts().CPlusPlus)
+ // Only a class or class template can take two or more arguments.
+ return NumArgs <= 1 || HasExplicitTemplateArgs || isa<CXXRecordDecl>(ND);
+
// Skip the current candidate if it is not a FunctionDecl or does not accept
// the current number of arguments.
if (!FD || !(FD->getNumParams() >= NumArgs &&
@@ -5032,7 +5169,8 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
return PD->getDefinition();
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
- return getDefinitionToImport(TD->getTemplatedDecl());
+ if (NamedDecl *TTD = TD->getTemplatedDecl())
+ return getDefinitionToImport(TTD);
return nullptr;
}
@@ -5052,17 +5190,18 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
auto Merged = Context.getModulesWithMergedDefinition(Def);
OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end());
- diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK,
+ diagnoseMissingImport(Loc, Def, Def->getLocation(), OwningModules, MIK,
Recover);
}
/// 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);
+ const FileEntry *E,
+ llvm::StringRef IncludingFile) {
+ bool IsSystem = false;
+ auto Path = PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(
+ E, IncludingFile, &IsSystem);
return (IsSystem ? '<' : '"') + Path + (IsSystem ? '>' : '"');
}
@@ -5072,12 +5211,63 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
MissingImportKind MIK, bool Recover) {
assert(!Modules.empty());
+ auto NotePrevious = [&] {
+ unsigned DiagID;
+ switch (MIK) {
+ case MissingImportKind::Declaration:
+ DiagID = diag::note_previous_declaration;
+ break;
+ case MissingImportKind::Definition:
+ DiagID = diag::note_previous_definition;
+ break;
+ case MissingImportKind::DefaultArgument:
+ DiagID = diag::note_default_argument_declared_here;
+ break;
+ case MissingImportKind::ExplicitSpecialization:
+ DiagID = diag::note_explicit_specialization_declared_here;
+ break;
+ case MissingImportKind::PartialSpecialization:
+ DiagID = diag::note_partial_specialization_declared_here;
+ break;
+ }
+ Diag(DeclLoc, DiagID);
+ };
+
// Weed out duplicates from module list.
llvm::SmallVector<Module*, 8> UniqueModules;
llvm::SmallDenseSet<Module*, 8> UniqueModuleSet;
- for (auto *M : Modules)
+ for (auto *M : Modules) {
+ if (M->Kind == Module::GlobalModuleFragment)
+ continue;
if (UniqueModuleSet.insert(M).second)
UniqueModules.push_back(M);
+ }
+
+ llvm::StringRef IncludingFile;
+ if (const FileEntry *FE =
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc)))
+ IncludingFile = FE->tryGetRealPathName();
+
+ if (UniqueModules.empty()) {
+ // All candidates were global module fragments. Try to suggest a #include.
+ const FileEntry *E =
+ PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, Modules[0], DeclLoc);
+ // FIXME: Find a smart place to suggest inserting a #include, and add
+ // a FixItHint there.
+ Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment)
+ << (int)MIK << Decl << !!E
+ << (E ? getIncludeStringForHeader(PP, E, IncludingFile) : "");
+ // Produce a "previous" note if it will point to a header rather than some
+ // random global module fragment.
+ // FIXME: Suppress the note backtrace even under
+ // -fdiagnostics-show-note-include-stack.
+ if (E)
+ NotePrevious();
+ if (Recover)
+ createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]);
+ return;
+ }
+
Modules = UniqueModules;
if (Modules.size() > 1) {
@@ -5102,33 +5292,15 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
// 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);
+ << (int)MIK << Decl << Modules[0]->getFullModuleName()
+ << getIncludeStringForHeader(PP, E, IncludingFile);
} else {
// FIXME: Add a FixItHint that imports the corresponding module.
Diag(UseLoc, diag::err_module_unimported_use)
<< (int)MIK << Decl << Modules[0]->getFullModuleName();
}
- unsigned DiagID;
- switch (MIK) {
- case MissingImportKind::Declaration:
- DiagID = diag::note_previous_declaration;
- break;
- case MissingImportKind::Definition:
- DiagID = diag::note_previous_definition;
- break;
- case MissingImportKind::DefaultArgument:
- DiagID = diag::note_default_argument_declared_here;
- break;
- case MissingImportKind::ExplicitSpecialization:
- DiagID = diag::note_explicit_specialization_declared_here;
- break;
- case MissingImportKind::PartialSpecialization:
- DiagID = diag::note_partial_specialization_declared_here;
- break;
- }
- Diag(DeclLoc, DiagID);
+ NotePrevious();
// Try to recover by implicitly importing this module.
if (Recover)
diff --git a/lib/Sema/SemaModule.cpp b/lib/Sema/SemaModule.cpp
new file mode 100644
index 000000000000..10de0ca91221
--- /dev/null
+++ b/lib/Sema/SemaModule.cpp
@@ -0,0 +1,710 @@
+//===--- SemaModule.cpp - Semantic Analysis for Modules -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for modules (C++ modules syntax,
+// Objective-C modules syntax, and Clang header modules).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaInternal.h"
+
+using namespace clang;
+using namespace sema;
+
+static void checkModuleImportContext(Sema &S, Module *M,
+ SourceLocation ImportLoc, DeclContext *DC,
+ bool FromInclude = false) {
+ SourceLocation ExternCLoc;
+
+ if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
+ switch (LSD->getLanguage()) {
+ case LinkageSpecDecl::lang_c:
+ if (ExternCLoc.isInvalid())
+ ExternCLoc = LSD->getBeginLoc();
+ break;
+ case LinkageSpecDecl::lang_cxx:
+ break;
+ }
+ DC = LSD->getParent();
+ }
+
+ while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC))
+ DC = DC->getParent();
+
+ if (!isa<TranslationUnitDecl>(DC)) {
+ S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M))
+ ? diag::ext_module_import_not_at_top_level_noop
+ : diag::err_module_import_not_at_top_level_fatal)
+ << M->getFullModuleName() << DC;
+ S.Diag(cast<Decl>(DC)->getBeginLoc(),
+ diag::note_module_import_not_at_top_level)
+ << DC;
+ } else if (!M->IsExternC && ExternCLoc.isValid()) {
+ S.Diag(ImportLoc, diag::ext_module_import_in_extern_c)
+ << M->getFullModuleName();
+ S.Diag(ExternCLoc, diag::note_extern_c_begins_here);
+ }
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) {
+ // Under -std=c++2a -fmodules-ts, we can find an explicit 'module;' after
+ // already implicitly entering the global module fragment. That's OK.
+ assert(getLangOpts().CPlusPlusModules && getLangOpts().ModulesTS &&
+ "unexpectedly encountered multiple global module fragment decls");
+ ModuleScopes.back().BeginLoc = ModuleLoc;
+ return nullptr;
+ }
+
+ // We start in the global module; all those declarations are implicitly
+ // module-private (though they do not have module linkage).
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ auto *GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(ModuleLoc);
+ assert(GlobalModule && "module creation should not fail");
+
+ // Enter the scope of the global module.
+ ModuleScopes.push_back({});
+ ModuleScopes.back().BeginLoc = ModuleLoc;
+ ModuleScopes.back().Module = GlobalModule;
+ VisibleModules.setVisible(GlobalModule, ModuleLoc);
+
+ // All declarations created from now on are owned by the global module.
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+ TU->setLocalOwningModule(GlobalModule);
+
+ // FIXME: Consider creating an explicit representation of this declaration.
+ return nullptr;
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
+ ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) {
+ assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) &&
+ "should only have module decl in Modules TS or C++20");
+
+ // A module implementation unit requires that we are not compiling a module
+ // of any kind. A module interface unit requires that we are not compiling a
+ // module map.
+ switch (getLangOpts().getCompilingModule()) {
+ case LangOptions::CMK_None:
+ // It's OK to compile a module interface as a normal translation unit.
+ break;
+
+ case LangOptions::CMK_ModuleInterface:
+ if (MDK != ModuleDeclKind::Implementation)
+ break;
+
+ // We were asked to compile a module interface unit but this is a module
+ // implementation unit. That indicates the 'export' is missing.
+ Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
+ << FixItHint::CreateInsertion(ModuleLoc, "export ");
+ MDK = ModuleDeclKind::Interface;
+ break;
+
+ case LangOptions::CMK_ModuleMap:
+ Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
+ return nullptr;
+
+ case LangOptions::CMK_HeaderModule:
+ Diag(ModuleLoc, diag::err_module_decl_in_header_module);
+ return nullptr;
+ }
+
+ assert(ModuleScopes.size() <= 1 && "expected to be at global module scope");
+
+ // FIXME: Most of this work should be done by the preprocessor rather than
+ // here, in order to support macro import.
+
+ // Only one module-declaration is permitted per source file.
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->isModulePurview()) {
+ Diag(ModuleLoc, diag::err_module_redeclaration);
+ Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
+ diag::note_prev_module_declaration);
+ return nullptr;
+ }
+
+ // Find the global module fragment we're adopting into this module, if any.
+ Module *GlobalModuleFragment = nullptr;
+ if (!ModuleScopes.empty() &&
+ ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment)
+ GlobalModuleFragment = ModuleScopes.back().Module;
+
+ // In C++20, the module-declaration must be the first declaration if there
+ // is no global module fragment.
+ if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !GlobalModuleFragment) {
+ Diag(ModuleLoc, diag::err_module_decl_not_at_start);
+ SourceLocation BeginLoc =
+ ModuleScopes.empty()
+ ? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID())
+ : ModuleScopes.back().BeginLoc;
+ if (BeginLoc.isValid()) {
+ Diag(BeginLoc, diag::note_global_module_introducer_missing)
+ << FixItHint::CreateInsertion(BeginLoc, "module;\n");
+ }
+ }
+
+ // Flatten the dots in a module name. Unlike Clang's hierarchical module map
+ // modules, the dots here are just another character that can appear in a
+ // module name.
+ std::string ModuleName;
+ for (auto &Piece : Path) {
+ if (!ModuleName.empty())
+ ModuleName += ".";
+ ModuleName += Piece.first->getName();
+ }
+
+ // If a module name was explicitly specified on the command line, it must be
+ // correct.
+ if (!getLangOpts().CurrentModule.empty() &&
+ getLangOpts().CurrentModule != ModuleName) {
+ Diag(Path.front().second, diag::err_current_module_name_mismatch)
+ << SourceRange(Path.front().second, Path.back().second)
+ << getLangOpts().CurrentModule;
+ return nullptr;
+ }
+ const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName;
+
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ Module *Mod;
+
+ switch (MDK) {
+ case ModuleDeclKind::Interface: {
+ // We can't have parsed or imported a definition of this module or parsed a
+ // module map defining it already.
+ if (auto *M = Map.findModule(ModuleName)) {
+ Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
+ if (M->DefinitionLoc.isValid())
+ Diag(M->DefinitionLoc, diag::note_prev_module_definition);
+ else if (const auto *FE = M->getASTFile())
+ Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
+ << FE->getName();
+ Mod = M;
+ break;
+ }
+
+ // Create a Module for the module that we're defining.
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ GlobalModuleFragment);
+ assert(Mod && "module creation should not fail");
+ break;
+ }
+
+ case ModuleDeclKind::Implementation:
+ std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
+ PP.getIdentifierInfo(ModuleName), Path[0].second);
+ Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
+ Module::AllVisible,
+ /*IsInclusionDirective=*/false);
+ if (!Mod) {
+ Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
+ // Create an empty module interface unit for error recovery.
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ GlobalModuleFragment);
+ }
+ break;
+ }
+
+ if (!GlobalModuleFragment) {
+ ModuleScopes.push_back({});
+ if (getLangOpts().ModulesLocalVisibility)
+ ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
+ } else {
+ // We're done with the global module fragment now.
+ ActOnEndOfTranslationUnitFragment(TUFragmentKind::Global);
+ }
+
+ // Switch from the global module fragment (if any) to the named module.
+ ModuleScopes.back().BeginLoc = StartLoc;
+ ModuleScopes.back().Module = Mod;
+ ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
+ VisibleModules.setVisible(Mod, ModuleLoc);
+
+ // From now on, we have an owning module for all declarations we see.
+ // However, those declarations are module-private unless explicitly
+ // exported.
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ TU->setLocalOwningModule(Mod);
+
+ // FIXME: Create a ModuleDecl.
+ return nullptr;
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc,
+ SourceLocation PrivateLoc) {
+ // C++20 [basic.link]/2:
+ // A private-module-fragment shall appear only in a primary module
+ // interface unit.
+ switch (ModuleScopes.empty() ? Module::GlobalModuleFragment
+ : ModuleScopes.back().Module->Kind) {
+ case Module::ModuleMapModule:
+ case Module::GlobalModuleFragment:
+ Diag(PrivateLoc, diag::err_private_module_fragment_not_module);
+ return nullptr;
+
+ case Module::PrivateModuleFragment:
+ Diag(PrivateLoc, diag::err_private_module_fragment_redefined);
+ Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition);
+ return nullptr;
+
+ case Module::ModuleInterfaceUnit:
+ break;
+ }
+
+ if (!ModuleScopes.back().ModuleInterface) {
+ Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface);
+ Diag(ModuleScopes.back().BeginLoc,
+ diag::note_not_module_interface_add_export)
+ << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export ");
+ return nullptr;
+ }
+
+ // FIXME: Check this isn't a module interface partition.
+ // FIXME: Check that this translation unit does not import any partitions;
+ // such imports would violate [basic.link]/2's "shall be the only module unit"
+ // restriction.
+
+ // We've finished the public fragment of the translation unit.
+ ActOnEndOfTranslationUnitFragment(TUFragmentKind::Normal);
+
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ Module *PrivateModuleFragment =
+ Map.createPrivateModuleFragmentForInterfaceUnit(
+ ModuleScopes.back().Module, PrivateLoc);
+ assert(PrivateModuleFragment && "module creation should not fail");
+
+ // Enter the scope of the private module fragment.
+ ModuleScopes.push_back({});
+ ModuleScopes.back().BeginLoc = ModuleLoc;
+ ModuleScopes.back().Module = PrivateModuleFragment;
+ ModuleScopes.back().ModuleInterface = true;
+ VisibleModules.setVisible(PrivateModuleFragment, ModuleLoc);
+
+ // All declarations created from now on are scoped to the private module
+ // fragment (and are neither visible nor reachable in importers of the module
+ // interface).
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ TU->setLocalOwningModule(PrivateModuleFragment);
+
+ // FIXME: Consider creating an explicit representation of this declaration.
+ return nullptr;
+}
+
+DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
+ SourceLocation ExportLoc,
+ SourceLocation ImportLoc,
+ ModuleIdPath Path) {
+ // Flatten the module path for a Modules TS module name.
+ std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
+ if (getLangOpts().ModulesTS) {
+ std::string ModuleName;
+ for (auto &Piece : Path) {
+ if (!ModuleName.empty())
+ ModuleName += ".";
+ ModuleName += Piece.first->getName();
+ }
+ ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second};
+ Path = ModuleIdPath(ModuleNameLoc);
+ }
+
+ Module *Mod =
+ getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
+ /*IsInclusionDirective=*/false);
+ if (!Mod)
+ return true;
+
+ return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path);
+}
+
+/// Determine whether \p D is lexically within an export-declaration.
+static const ExportDecl *getEnclosingExportDecl(const Decl *D) {
+ for (auto *DC = D->getLexicalDeclContext(); DC; DC = DC->getLexicalParent())
+ if (auto *ED = dyn_cast<ExportDecl>(DC))
+ return ED;
+ return nullptr;
+}
+
+DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
+ SourceLocation ExportLoc,
+ SourceLocation ImportLoc,
+ Module *Mod, ModuleIdPath Path) {
+ VisibleModules.setVisible(Mod, ImportLoc);
+
+ checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
+
+ // FIXME: we should support importing a submodule within a different submodule
+ // of the same top-level module. Until we do, make it an error rather than
+ // silently ignoring the import.
+ // Import-from-implementation is valid in the Modules TS. FIXME: Should we
+ // warn on a redundant import of the current module?
+ // FIXME: Import of a module from an implementation partition of the same
+ // module is permitted.
+ if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
+ (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
+ Diag(ImportLoc, getLangOpts().isCompilingModule()
+ ? diag::err_module_self_import
+ : diag::err_module_import_in_implementation)
+ << Mod->getFullModuleName() << getLangOpts().CurrentModule;
+ }
+
+ SmallVector<SourceLocation, 2> IdentifierLocs;
+ Module *ModCheck = Mod;
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ // If we've run out of module parents, just drop the remaining identifiers.
+ // We need the length to be consistent.
+ if (!ModCheck)
+ break;
+ ModCheck = ModCheck->Parent;
+
+ IdentifierLocs.push_back(Path[I].second);
+ }
+
+ // If this was a header import, pad out with dummy locations.
+ // FIXME: Pass in and use the location of the header-name token in this case.
+ if (Path.empty()) {
+ for (; ModCheck; ModCheck = ModCheck->Parent) {
+ IdentifierLocs.push_back(SourceLocation());
+ }
+ }
+
+ ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc,
+ Mod, IdentifierLocs);
+ CurContext->addDecl(Import);
+
+ // Sequence initialization of the imported module before that of the current
+ // module, if any.
+ if (!ModuleScopes.empty())
+ Context.addModuleInitializer(ModuleScopes.back().Module, Import);
+
+ // Re-export the module if needed.
+ if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) {
+ if (ExportLoc.isValid() || getEnclosingExportDecl(Import))
+ getCurrentModule()->Exports.emplace_back(Mod, false);
+ } else if (ExportLoc.isValid()) {
+ Diag(ExportLoc, diag::err_export_not_in_module_interface);
+ }
+
+ return Import;
+}
+
+void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
+ BuildModuleInclude(DirectiveLoc, Mod);
+}
+
+void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
+ // Determine whether we're in the #include buffer for a module. The #includes
+ // in that buffer do not qualify as module imports; they're just an
+ // implementation detail of us building the module.
+ //
+ // FIXME: Should we even get ActOnModuleInclude calls for those?
+ bool IsInModuleIncludes =
+ TUKind == TU_Module &&
+ getSourceManager().isWrittenInMainFile(DirectiveLoc);
+
+ bool ShouldAddImport = !IsInModuleIncludes;
+
+ // If this module import was due to an inclusion directive, create an
+ // implicit import declaration to capture it in the AST.
+ if (ShouldAddImport) {
+ TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
+ ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+ DirectiveLoc, Mod,
+ DirectiveLoc);
+ if (!ModuleScopes.empty())
+ Context.addModuleInitializer(ModuleScopes.back().Module, ImportD);
+ TU->addDecl(ImportD);
+ Consumer.HandleImplicitImportDecl(ImportD);
+ }
+
+ getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc);
+ VisibleModules.setVisible(Mod, DirectiveLoc);
+}
+
+void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
+
+ ModuleScopes.push_back({});
+ ModuleScopes.back().Module = Mod;
+ if (getLangOpts().ModulesLocalVisibility)
+ ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
+
+ VisibleModules.setVisible(Mod, DirectiveLoc);
+
+ // The enclosing context is now part of this module.
+ // FIXME: Consider creating a child DeclContext to hold the entities
+ // lexically within the module.
+ if (getLangOpts().trackLocalOwningModule()) {
+ for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ getLangOpts().ModulesLocalVisibility
+ ? Decl::ModuleOwnershipKind::VisibleWhenImported
+ : Decl::ModuleOwnershipKind::Visible);
+ cast<Decl>(DC)->setLocalOwningModule(Mod);
+ }
+ }
+}
+
+void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
+ if (getLangOpts().ModulesLocalVisibility) {
+ VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules);
+ // Leaving a module hides namespace names, so our visible namespace cache
+ // is now out of date.
+ VisibleNamespaceCache.clear();
+ }
+
+ assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod &&
+ "left the wrong module scope");
+ ModuleScopes.pop_back();
+
+ // We got to the end of processing a local module. Create an
+ // ImportDecl as we would for an imported module.
+ FileID File = getSourceManager().getFileID(EomLoc);
+ SourceLocation DirectiveLoc;
+ if (EomLoc == getSourceManager().getLocForEndOfFile(File)) {
+ // We reached the end of a #included module header. Use the #include loc.
+ assert(File != getSourceManager().getMainFileID() &&
+ "end of submodule in main source file");
+ DirectiveLoc = getSourceManager().getIncludeLoc(File);
+ } else {
+ // We reached an EOM pragma. Use the pragma location.
+ DirectiveLoc = EomLoc;
+ }
+ BuildModuleInclude(DirectiveLoc, Mod);
+
+ // Any further declarations are in whatever module we returned to.
+ if (getLangOpts().trackLocalOwningModule()) {
+ // The parser guarantees that this is the same context that we entered
+ // the module within.
+ for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ cast<Decl>(DC)->setLocalOwningModule(getCurrentModule());
+ if (!getCurrentModule())
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::Unowned);
+ }
+ }
+}
+
+void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
+ Module *Mod) {
+ // Bail if we're not allowed to implicitly import a module here.
+ if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery ||
+ VisibleModules.isVisible(Mod))
+ return;
+
+ // Create the implicit import declaration.
+ TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
+ ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+ Loc, Mod, Loc);
+ TU->addDecl(ImportD);
+ Consumer.HandleImplicitImportDecl(ImportD);
+
+ // Make the module visible.
+ getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc);
+ VisibleModules.setVisible(Mod, Loc);
+}
+
+/// We have parsed the start of an export declaration, including the '{'
+/// (if present).
+Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
+ SourceLocation LBraceLoc) {
+ ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
+
+ // Set this temporarily so we know the export-declaration was braced.
+ D->setRBraceLoc(LBraceLoc);
+
+ // C++2a [module.interface]p1:
+ // An export-declaration shall appear only [...] in the purview of a module
+ // interface unit. An export-declaration shall not appear directly or
+ // indirectly within [...] a private-module-fragment.
+ if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) {
+ Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
+ } else if (!ModuleScopes.back().ModuleInterface) {
+ Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1;
+ Diag(ModuleScopes.back().BeginLoc,
+ diag::note_not_module_interface_add_export)
+ << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export ");
+ } else if (ModuleScopes.back().Module->Kind ==
+ Module::PrivateModuleFragment) {
+ Diag(ExportLoc, diag::err_export_in_private_module_fragment);
+ Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment);
+ }
+
+ for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) {
+ // An export-declaration shall not appear directly or indirectly within
+ // an unnamed namespace [...]
+ if (ND->isAnonymousNamespace()) {
+ Diag(ExportLoc, diag::err_export_within_anonymous_namespace);
+ Diag(ND->getLocation(), diag::note_anonymous_namespace);
+ // Don't diagnose internal-linkage declarations in this region.
+ D->setInvalidDecl();
+ break;
+ }
+
+ // A declaration is exported if it is [...] a namespace-definition
+ // that contains an exported declaration.
+ //
+ // Defer exporting the namespace until after we leave it, in order to
+ // avoid marking all subsequent declarations in the namespace as exported.
+ if (!DeferredExportedNamespaces.insert(ND).second)
+ break;
+ }
+ }
+
+ // [...] its declaration or declaration-seq shall not contain an
+ // export-declaration.
+ if (auto *ED = getEnclosingExportDecl(D)) {
+ Diag(ExportLoc, diag::err_export_within_export);
+ if (ED->hasBraces())
+ Diag(ED->getLocation(), diag::note_export);
+ }
+
+ CurContext->addDecl(D);
+ PushDeclContext(S, D);
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported);
+ return D;
+}
+
+static bool checkExportedDeclContext(Sema &S, DeclContext *DC,
+ SourceLocation BlockStart);
+
+namespace {
+enum class UnnamedDeclKind {
+ Empty,
+ StaticAssert,
+ Asm,
+ UsingDirective,
+ Context
+};
+}
+
+static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
+ if (isa<EmptyDecl>(D))
+ return UnnamedDeclKind::Empty;
+ if (isa<StaticAssertDecl>(D))
+ return UnnamedDeclKind::StaticAssert;
+ if (isa<FileScopeAsmDecl>(D))
+ return UnnamedDeclKind::Asm;
+ if (isa<UsingDirectiveDecl>(D))
+ return UnnamedDeclKind::UsingDirective;
+ // Everything else either introduces one or more names or is ill-formed.
+ return llvm::None;
+}
+
+unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) {
+ switch (UDK) {
+ case UnnamedDeclKind::Empty:
+ case UnnamedDeclKind::StaticAssert:
+ // Allow empty-declarations and static_asserts in an export block as an
+ // extension.
+ return InBlock ? diag::ext_export_no_name_block : diag::err_export_no_name;
+
+ case UnnamedDeclKind::UsingDirective:
+ // Allow exporting using-directives as an extension.
+ return diag::ext_export_using_directive;
+
+ case UnnamedDeclKind::Context:
+ // Allow exporting DeclContexts that transitively contain no declarations
+ // as an extension.
+ return diag::ext_export_no_names;
+
+ case UnnamedDeclKind::Asm:
+ return diag::err_export_no_name;
+ }
+ llvm_unreachable("unknown kind");
+}
+
+static void diagExportedUnnamedDecl(Sema &S, UnnamedDeclKind UDK, Decl *D,
+ SourceLocation BlockStart) {
+ S.Diag(D->getLocation(), getUnnamedDeclDiag(UDK, BlockStart.isValid()))
+ << (unsigned)UDK;
+ if (BlockStart.isValid())
+ S.Diag(BlockStart, diag::note_export);
+}
+
+/// Check that it's valid to export \p D.
+static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
+ // C++2a [module.interface]p3:
+ // An exported declaration shall declare at least one name
+ if (auto UDK = getUnnamedDeclKind(D))
+ diagExportedUnnamedDecl(S, *UDK, D, BlockStart);
+
+ // [...] shall not declare a name with internal linkage.
+ if (auto *ND = dyn_cast<NamedDecl>(D)) {
+ // Don't diagnose anonymous union objects; we'll diagnose their members
+ // instead.
+ if (ND->getDeclName() && ND->getFormalLinkage() == InternalLinkage) {
+ S.Diag(ND->getLocation(), diag::err_export_internal) << ND;
+ if (BlockStart.isValid())
+ S.Diag(BlockStart, diag::note_export);
+ }
+ }
+
+ // C++2a [module.interface]p5:
+ // all entities to which all of the using-declarators ultimately refer
+ // shall have been introduced with a name having external linkage
+ if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
+ NamedDecl *Target = USD->getUnderlyingDecl();
+ if (Target->getFormalLinkage() == InternalLinkage) {
+ S.Diag(USD->getLocation(), diag::err_export_using_internal) << Target;
+ S.Diag(Target->getLocation(), diag::note_using_decl_target);
+ if (BlockStart.isValid())
+ S.Diag(BlockStart, diag::note_export);
+ }
+ }
+
+ // Recurse into namespace-scope DeclContexts. (Only namespace-scope
+ // declarations are exported.)
+ if (auto *DC = dyn_cast<DeclContext>(D))
+ if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D))
+ return checkExportedDeclContext(S, DC, BlockStart);
+ return false;
+}
+
+/// Check that it's valid to export all the declarations in \p DC.
+static bool checkExportedDeclContext(Sema &S, DeclContext *DC,
+ SourceLocation BlockStart) {
+ bool AllUnnamed = true;
+ for (auto *D : DC->decls())
+ AllUnnamed &= checkExportedDecl(S, D, BlockStart);
+ return AllUnnamed;
+}
+
+/// Complete the definition of an export declaration.
+Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
+ auto *ED = cast<ExportDecl>(D);
+ if (RBraceLoc.isValid())
+ ED->setRBraceLoc(RBraceLoc);
+
+ PopDeclContext();
+
+ if (!D->isInvalidDecl()) {
+ SourceLocation BlockStart =
+ ED->hasBraces() ? ED->getBeginLoc() : SourceLocation();
+ for (auto *Child : ED->decls()) {
+ if (checkExportedDecl(*this, Child, BlockStart)) {
+ // If a top-level child is a linkage-spec declaration, it might contain
+ // no declarations (transitively), in which case it's ill-formed.
+ diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child,
+ BlockStart);
+ }
+ }
+ }
+
+ return D;
+}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 9412d0160048..e5c014501431 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -1,9 +1,8 @@
//===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -1289,7 +1288,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
- PropertyIvarType, /*Dinfo=*/nullptr,
+ PropertyIvarType, /*TInfo=*/nullptr,
ObjCIvarDecl::Private,
(Expr *)nullptr, true);
if (RequireNonAbstractType(PropertyIvarLoc,
@@ -1943,11 +1942,10 @@ static void DiagnoseUnimplementedAccessor(
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();
- });
+ auto I = llvm::find_if(SMap, [&](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,
@@ -2281,9 +2279,18 @@ void Sema::DiagnoseMissingDesignatedInitOverrides(
I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {
const ObjCMethodDecl *MD = *I;
if (!InitSelSet.count(MD->getSelector())) {
+ // Don't emit a diagnostic if the overriding method in the subclass is
+ // marked as unavailable.
bool Ignore = false;
if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) {
Ignore = IMD->isUnavailable();
+ } else {
+ // Check the methods declared in the class extensions too.
+ for (auto *Ext : IFD->visible_extensions())
+ if (auto *IMD = Ext->getInstanceMethod(MD->getSelector())) {
+ Ignore = IMD->isUnavailable();
+ break;
+ }
}
if (!Ignore) {
Diag(ImplD->getLocation(),
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 36048a38b999..bd68011c18b2 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -1,9 +1,8 @@
//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -135,7 +134,7 @@ private:
/// get the data (loop counters etc.) about enclosing loop-based construct.
/// This data is required during codegen.
DoacrossDependMapTy DoacrossDepends;
- /// first argument (Expr *) contains optional argument of the
+ /// First argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
@@ -144,10 +143,14 @@ private:
bool NowaitRegion = false;
bool CancelRegion = false;
bool LoopStart = false;
+ bool BodyComplete = false;
SourceLocation InnerTeamsRegionLoc;
/// Reference to the taskgroup task_reduction reference expression.
Expr *TaskgroupReductionRef = nullptr;
llvm::DenseSet<QualType> MappedClassesQualTypes;
+ /// List of globals marked as declare target link in this target region
+ /// (isOpenMPTargetExecutionDirective(Directive) == true).
+ llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -170,26 +173,112 @@ private:
/// captured by reference.
bool ForceCaptureByReferenceInTargetExecutable = false;
CriticalsWithHintsTy Criticals;
+ unsigned IgnoredStackElements = 0;
- using iterator = StackTy::const_reverse_iterator;
+ /// Iterators over the stack iterate in order from innermost to outermost
+ /// directive.
+ using const_iterator = StackTy::const_reverse_iterator;
+ const_iterator begin() const {
+ return Stack.empty() ? const_iterator()
+ : Stack.back().first.rbegin() + IgnoredStackElements;
+ }
+ const_iterator end() const {
+ return Stack.empty() ? const_iterator() : Stack.back().first.rend();
+ }
+ using iterator = StackTy::reverse_iterator;
+ iterator begin() {
+ return Stack.empty() ? iterator()
+ : Stack.back().first.rbegin() + IgnoredStackElements;
+ }
+ iterator end() {
+ return Stack.empty() ? iterator() : Stack.back().first.rend();
+ }
- DSAVarData getDSA(iterator &Iter, ValueDecl *D) const;
-
- /// Checks if the variable is a local for OpenMP region.
- bool isOpenMPLocal(VarDecl *D, iterator Iter) const;
+ // Convenience operations to get at the elements of the stack.
bool isStackEmpty() const {
return Stack.empty() ||
Stack.back().second != CurrentNonCapturingFunctionScope ||
- Stack.back().first.empty();
+ Stack.back().first.size() <= IgnoredStackElements;
+ }
+ size_t getStackSize() const {
+ return isStackEmpty() ? 0
+ : Stack.back().first.size() - IgnoredStackElements;
+ }
+
+ SharingMapTy *getTopOfStackOrNull() {
+ size_t Size = getStackSize();
+ if (Size == 0)
+ return nullptr;
+ return &Stack.back().first[Size - 1];
}
+ const SharingMapTy *getTopOfStackOrNull() const {
+ return const_cast<DSAStackTy&>(*this).getTopOfStackOrNull();
+ }
+ SharingMapTy &getTopOfStack() {
+ assert(!isStackEmpty() && "no current directive");
+ return *getTopOfStackOrNull();
+ }
+ const SharingMapTy &getTopOfStack() const {
+ return const_cast<DSAStackTy&>(*this).getTopOfStack();
+ }
+
+ SharingMapTy *getSecondOnStackOrNull() {
+ size_t Size = getStackSize();
+ if (Size <= 1)
+ return nullptr;
+ return &Stack.back().first[Size - 2];
+ }
+ const SharingMapTy *getSecondOnStackOrNull() const {
+ return const_cast<DSAStackTy&>(*this).getSecondOnStackOrNull();
+ }
+
+ /// Get the stack element at a certain level (previously returned by
+ /// \c getNestingLevel).
+ ///
+ /// Note that nesting levels count from outermost to innermost, and this is
+ /// the reverse of our iteration order where new inner levels are pushed at
+ /// the front of the stack.
+ SharingMapTy &getStackElemAtLevel(unsigned Level) {
+ assert(Level < getStackSize() && "no such stack element");
+ return Stack.back().first[Level];
+ }
+ const SharingMapTy &getStackElemAtLevel(unsigned Level) const {
+ return const_cast<DSAStackTy&>(*this).getStackElemAtLevel(Level);
+ }
+
+ DSAVarData getDSA(const_iterator &Iter, ValueDecl *D) const;
+
+ /// Checks if the variable is a local for OpenMP region.
+ bool isOpenMPLocal(VarDecl *D, const_iterator Iter) const;
/// Vector of previously declared requires directives
SmallVector<const OMPRequiresDecl *, 2> RequiresDecls;
+ /// omp_allocator_handle_t type.
+ QualType OMPAllocatorHandleT;
+ /// Expression for the predefined allocators.
+ Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = {
+ nullptr};
+ /// Vector of previously encountered target directives
+ SmallVector<SourceLocation, 2> TargetLocations;
public:
explicit DSAStackTy(Sema &S) : SemaRef(S) {}
+ /// Sets omp_allocator_handle_t type.
+ void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; }
+ /// Gets omp_allocator_handle_t type.
+ QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; }
+ /// Sets the given default allocator.
+ void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
+ Expr *Allocator) {
+ OMPPredefinedAllocators[AllocatorKind] = Allocator;
+ }
+ /// Returns the specified default allocator.
+ Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const {
+ return OMPPredefinedAllocators[AllocatorKind];
+ }
+
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
OpenMPClauseKind getClauseParsingMode() const {
assert(isClauseParsingMode() && "Must be in clause parsing mode.");
@@ -197,6 +286,14 @@ public:
}
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
+ bool isBodyComplete() const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top && Top->BodyComplete;
+ }
+ void setBodyComplete() {
+ getTopOfStack().BodyComplete = true;
+ }
+
bool isForceVarCapturing() const { return ForceCapturing; }
void setForceVarCapturing(bool V) { ForceCapturing = V; }
@@ -209,6 +306,8 @@ public:
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
if (Stack.empty() ||
Stack.back().second != CurrentNonCapturingFunctionScope)
Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope);
@@ -217,46 +316,78 @@ public:
}
void pop() {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
assert(!Stack.back().first.empty() &&
"Data-sharing attributes stack is empty!");
Stack.back().first.pop_back();
}
+ /// RAII object to temporarily leave the scope of a directive when we want to
+ /// logically operate in its parent.
+ class ParentDirectiveScope {
+ DSAStackTy &Self;
+ bool Active;
+ public:
+ ParentDirectiveScope(DSAStackTy &Self, bool Activate)
+ : Self(Self), Active(false) {
+ if (Activate)
+ enable();
+ }
+ ~ParentDirectiveScope() { disable(); }
+ void disable() {
+ if (Active) {
+ --Self.IgnoredStackElements;
+ Active = false;
+ }
+ }
+ void enable() {
+ if (!Active) {
+ ++Self.IgnoredStackElements;
+ Active = true;
+ }
+ }
+ };
+
/// Marks that we're started loop parsing.
void loopInit() {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
- Stack.back().first.back().LoopStart = true;
+ getTopOfStack().LoopStart = true;
}
/// Start capturing of the variables in the loop context.
void loopStart() {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
- Stack.back().first.back().LoopStart = false;
+ getTopOfStack().LoopStart = false;
}
/// true, if variables are captured, false otherwise.
bool isLoopStarted() const {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
- return !Stack.back().first.back().LoopStart;
+ return !getTopOfStack().LoopStart;
}
/// Marks (or clears) declaration as possibly loop counter.
void resetPossibleLoopCounter(const Decl *D = nullptr) {
- Stack.back().first.back().PossiblyLoopCounter =
+ getTopOfStack().PossiblyLoopCounter =
D ? D->getCanonicalDecl() : D;
}
/// Gets the possible loop counter decl.
const Decl *getPossiblyLoopCunter() const {
- return Stack.back().first.back().PossiblyLoopCounter;
+ return getTopOfStack().PossiblyLoopCounter;
}
/// Start new OpenMP region stack in new non-capturing function.
void pushFunction() {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
assert(!isa<CapturingScopeInfo>(CurFnScope));
CurrentNonCapturingFunctionScope = CurFnScope;
}
/// Pop region stack for non-capturing function.
void popFunction(const FunctionScopeInfo *OldFSI) {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
if (!Stack.empty() && Stack.back().second == OldFSI) {
assert(Stack.back().first.empty());
Stack.pop_back();
@@ -327,16 +458,16 @@ public:
Expr *&TaskgroupDescriptor) const;
/// Return reduction reference expression for the current taskgroup.
Expr *getTaskgroupReductionRef() const {
- assert(Stack.back().first.back().Directive == OMPD_taskgroup &&
+ assert(getTopOfStack().Directive == OMPD_taskgroup &&
"taskgroup reference expression requested for non taskgroup "
"directive.");
- return Stack.back().first.back().TaskgroupReductionRef;
+ return getTopOfStack().TaskgroupReductionRef;
}
/// Checks if the given \p VD declaration is actually a taskgroup reduction
/// descriptor variable at the \p Level of OpenMP regions.
bool isTaskgroupReductionRef(const ValueDecl *VD, unsigned Level) const {
- return Stack.back().first[Level].TaskgroupReductionRef &&
- cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef)
+ return getStackElemAtLevel(Level).TaskgroupReductionRef &&
+ cast<DeclRefExpr>(getStackElemAtLevel(Level).TaskgroupReductionRef)
->getDecl() == VD;
}
@@ -382,18 +513,18 @@ public:
/// Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
- return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->Directive : OMPD_unknown;
}
/// Returns directive kind at specified level.
OpenMPDirectiveKind getDirective(unsigned Level) const {
assert(!isStackEmpty() && "No directive at specified level.");
- return Stack.back().first[Level].Directive;
+ return getStackElemAtLevel(Level).Directive;
}
/// Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
- if (isStackEmpty() || Stack.back().first.size() == 1)
- return OMPD_unknown;
- return std::next(Stack.back().first.rbegin())->Directive;
+ const SharingMapTy *Parent = getSecondOnStackOrNull();
+ return Parent ? Parent->Directive : OMPD_unknown;
}
/// Add requires decl to internal vector
@@ -401,6 +532,16 @@ public:
RequiresDecls.push_back(RD);
}
+ /// Checks if the defined 'requires' directive has specified type of clause.
+ template <typename ClauseType>
+ bool hasRequiresDeclWithClause() {
+ return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) {
+ return llvm::any_of(D->clauselists(), [](const OMPClause *C) {
+ return isa<ClauseType>(C);
+ });
+ });
+ }
+
/// Checks for a duplicate clause amongst previously declared requires
/// directives
bool hasDuplicateRequiresClause(ArrayRef<OMPClause *> ClauseList) const {
@@ -423,43 +564,50 @@ public:
return IsDuplicate;
}
+ /// Add location of previously encountered target to internal vector
+ void addTargetDirLocation(SourceLocation LocStart) {
+ TargetLocations.push_back(LocStart);
+ }
+
+ // Return previously encountered target region locations.
+ ArrayRef<SourceLocation> getEncounteredTargetLocs() const {
+ return TargetLocations;
+ }
+
/// Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
- assert(!isStackEmpty());
- Stack.back().first.back().DefaultAttr = DSA_none;
- Stack.back().first.back().DefaultAttrLoc = Loc;
+ getTopOfStack().DefaultAttr = DSA_none;
+ getTopOfStack().DefaultAttrLoc = Loc;
}
/// Set default data sharing attribute to shared.
void setDefaultDSAShared(SourceLocation Loc) {
- assert(!isStackEmpty());
- Stack.back().first.back().DefaultAttr = DSA_shared;
- Stack.back().first.back().DefaultAttrLoc = Loc;
+ getTopOfStack().DefaultAttr = DSA_shared;
+ getTopOfStack().DefaultAttrLoc = Loc;
}
/// Set default data mapping attribute to 'tofrom:scalar'.
void setDefaultDMAToFromScalar(SourceLocation Loc) {
- assert(!isStackEmpty());
- Stack.back().first.back().DefaultMapAttr = DMA_tofrom_scalar;
- Stack.back().first.back().DefaultMapAttrLoc = Loc;
+ getTopOfStack().DefaultMapAttr = DMA_tofrom_scalar;
+ getTopOfStack().DefaultMapAttrLoc = Loc;
}
DefaultDataSharingAttributes getDefaultDSA() const {
return isStackEmpty() ? DSA_unspecified
- : Stack.back().first.back().DefaultAttr;
+ : getTopOfStack().DefaultAttr;
}
SourceLocation getDefaultDSALocation() const {
return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().DefaultAttrLoc;
+ : getTopOfStack().DefaultAttrLoc;
}
DefaultMapAttributes getDefaultDMA() const {
return isStackEmpty() ? DMA_unspecified
- : Stack.back().first.back().DefaultMapAttr;
+ : getTopOfStack().DefaultMapAttr;
}
DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
- return Stack.back().first[Level].DefaultMapAttr;
+ return getStackElemAtLevel(Level).DefaultMapAttr;
}
SourceLocation getDefaultDMALocation() const {
return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().DefaultMapAttrLoc;
+ : getTopOfStack().DefaultMapAttrLoc;
}
/// Checks if the specified variable is a threadprivate.
@@ -471,82 +619,77 @@ public:
/// Marks current region as ordered (it has an 'ordered' clause).
void setOrderedRegion(bool IsOrdered, const Expr *Param,
OMPOrderedClause *Clause) {
- assert(!isStackEmpty());
if (IsOrdered)
- Stack.back().first.back().OrderedRegion.emplace(Param, Clause);
+ getTopOfStack().OrderedRegion.emplace(Param, Clause);
else
- Stack.back().first.back().OrderedRegion.reset();
+ getTopOfStack().OrderedRegion.reset();
}
/// Returns true, if region is ordered (has associated 'ordered' clause),
/// false - otherwise.
bool isOrderedRegion() const {
- if (isStackEmpty())
- return false;
- return Stack.back().first.rbegin()->OrderedRegion.hasValue();
+ if (const SharingMapTy *Top = getTopOfStackOrNull())
+ return Top->OrderedRegion.hasValue();
+ return false;
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
- if (isStackEmpty() ||
- !Stack.back().first.rbegin()->OrderedRegion.hasValue())
- return std::make_pair(nullptr, nullptr);
- return Stack.back().first.rbegin()->OrderedRegion.getValue();
+ if (const SharingMapTy *Top = getTopOfStackOrNull())
+ if (Top->OrderedRegion.hasValue())
+ return Top->OrderedRegion.getValue();
+ return std::make_pair(nullptr, nullptr);
}
/// Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
- if (isStackEmpty() || Stack.back().first.size() == 1)
- return false;
- return std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue();
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ return Parent->OrderedRegion.hasValue();
+ return false;
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *>
getParentOrderedRegionParam() const {
- if (isStackEmpty() || Stack.back().first.size() == 1 ||
- !std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue())
- return std::make_pair(nullptr, nullptr);
- return std::next(Stack.back().first.rbegin())->OrderedRegion.getValue();
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ if (Parent->OrderedRegion.hasValue())
+ return Parent->OrderedRegion.getValue();
+ return std::make_pair(nullptr, nullptr);
}
/// Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
- assert(!isStackEmpty());
- Stack.back().first.back().NowaitRegion = IsNowait;
+ getTopOfStack().NowaitRegion = IsNowait;
}
/// Returns true, if parent region is nowait (has associated
/// 'nowait' clause), false - otherwise.
bool isParentNowaitRegion() const {
- if (isStackEmpty() || Stack.back().first.size() == 1)
- return false;
- return std::next(Stack.back().first.rbegin())->NowaitRegion;
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ return Parent->NowaitRegion;
+ return false;
}
/// Marks parent region as cancel region.
void setParentCancelRegion(bool Cancel = true) {
- if (!isStackEmpty() && Stack.back().first.size() > 1) {
- auto &StackElemRef = *std::next(Stack.back().first.rbegin());
- StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel;
- }
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->CancelRegion |= Cancel;
}
/// Return true if current region has inner cancel construct.
bool isCancelRegion() const {
- return isStackEmpty() ? false : Stack.back().first.back().CancelRegion;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->CancelRegion : false;
}
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
- assert(!isStackEmpty());
- Stack.back().first.back().AssociatedLoops = Val;
+ getTopOfStack().AssociatedLoops = Val;
}
/// Return collapse value for region.
unsigned getAssociatedLoops() const {
- return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->AssociatedLoops : 0;
}
/// Marks current target region as one with closely nested teams
/// region.
void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
- if (!isStackEmpty() && Stack.back().first.size() > 1) {
- std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc =
- TeamsRegionLoc;
- }
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->InnerTeamsRegionLoc = TeamsRegionLoc;
}
/// Returns true, if current region has closely nested teams region.
bool hasInnerTeamsRegion() const {
@@ -554,16 +697,17 @@ public:
}
/// Returns location of the nested teams region (if any).
SourceLocation getInnerTeamsRegionLoc() const {
- return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().InnerTeamsRegionLoc;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->InnerTeamsRegionLoc : SourceLocation();
}
Scope *getCurScope() const {
- return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->CurScope : nullptr;
}
SourceLocation getConstructLoc() const {
- return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().ConstructLoc;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->ConstructLoc : SourceLocation();
}
/// Do the check specified in \a Check to all component lists and return true
@@ -576,8 +720,8 @@ public:
Check) const {
if (isStackEmpty())
return false;
- auto SI = Stack.back().first.rbegin();
- auto SE = Stack.back().first.rend();
+ auto SI = begin();
+ auto SE = end();
if (SI == SE)
return false;
@@ -606,17 +750,12 @@ public:
bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind)>
Check) const {
- if (isStackEmpty())
- return false;
-
- auto StartI = Stack.back().first.begin();
- auto EndI = Stack.back().first.end();
- if (std::distance(StartI, EndI) <= (int)Level)
+ if (getStackSize() <= Level)
return false;
- std::advance(StartI, Level);
- auto MI = StartI->MappedExprComponents.find(VD);
- if (MI != StartI->MappedExprComponents.end())
+ const SharingMapTy &StackElem = getStackElemAtLevel(Level);
+ auto MI = StackElem.MappedExprComponents.find(VD);
+ if (MI != StackElem.MappedExprComponents.end())
for (OMPClauseMappableExprCommon::MappableExprComponentListRef L :
MI->second.Components)
if (Check(L, MI->second.Kind))
@@ -630,10 +769,7 @@ public:
const ValueDecl *VD,
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
OpenMPClauseKind WhereFoundClauseKind) {
- assert(!isStackEmpty() &&
- "Not expecting to retrieve components from a empty stack!");
- MappedExprComponentTy &MEC =
- Stack.back().first.back().MappedExprComponents[VD];
+ MappedExprComponentTy &MEC = getTopOfStack().MappedExprComponents[VD];
// Create new entry and append the new components there.
MEC.Components.resize(MEC.Components.size() + 1);
MEC.Components.back().append(Components.begin(), Components.end());
@@ -642,19 +778,17 @@ public:
unsigned getNestingLevel() const {
assert(!isStackEmpty());
- return Stack.back().first.size() - 1;
+ return getStackSize() - 1;
}
void addDoacrossDependClause(OMPDependClause *C,
const OperatorOffsetTy &OpsOffs) {
- assert(!isStackEmpty() && Stack.back().first.size() > 1);
- SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
- assert(isOpenMPWorksharingDirective(StackElem.Directive));
- StackElem.DoacrossDepends.try_emplace(C, OpsOffs);
+ SharingMapTy *Parent = getSecondOnStackOrNull();
+ assert(Parent && isOpenMPWorksharingDirective(Parent->Directive));
+ Parent->DoacrossDepends.try_emplace(C, OpsOffs);
}
llvm::iterator_range<DoacrossDependMapTy::const_iterator>
getDoacrossDependClauses() const {
- assert(!isStackEmpty());
- const SharingMapTy &StackElem = Stack.back().first.back();
+ const SharingMapTy &StackElem = getTopOfStack();
if (isOpenMPWorksharingDirective(StackElem.Directive)) {
const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends;
return llvm::make_range(Ref.begin(), Ref.end());
@@ -665,16 +799,36 @@ public:
// Store types of classes which have been explicitly mapped
void addMappedClassesQualTypes(QualType QT) {
- SharingMapTy &StackElem = Stack.back().first.back();
+ SharingMapTy &StackElem = getTopOfStack();
StackElem.MappedClassesQualTypes.insert(QT);
}
// Return set of mapped classes types
bool isClassPreviouslyMapped(QualType QT) const {
- const SharingMapTy &StackElem = Stack.back().first.back();
+ const SharingMapTy &StackElem = getTopOfStack();
return StackElem.MappedClassesQualTypes.count(QT) != 0;
}
+ /// Adds global declare target to the parent target region.
+ void addToParentTargetRegionLinkGlobals(DeclRefExpr *E) {
+ assert(*OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
+ E->getDecl()) == OMPDeclareTargetDeclAttr::MT_Link &&
+ "Expected declare target link global.");
+ for (auto &Elem : *this) {
+ if (isOpenMPTargetExecutionDirective(Elem.Directive)) {
+ Elem.DeclareTargetLinkVarDecls.push_back(E);
+ return;
+ }
+ }
+ }
+
+ /// Returns the list of globals with declare target link if current directive
+ /// is target.
+ ArrayRef<DeclRefExpr *> getLinkGlobals() const {
+ assert(isOpenMPTargetExecutionDirective(getCurrentDirective()) &&
+ "Expected target executable directive.");
+ return getTopOfStack().DeclareTargetLinkVarDecls;
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -682,7 +836,8 @@ bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
}
bool isImplicitOrExplicitTaskingRegion(OpenMPDirectiveKind DKind) {
- return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || DKind == OMPD_unknown;
+ return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) ||
+ DKind == OMPD_unknown;
}
} // namespace
@@ -728,13 +883,13 @@ static ValueDecl *getCanonicalDecl(ValueDecl *D) {
getCanonicalDecl(const_cast<const ValueDecl *>(D)));
}
-DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter,
+DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
ValueDecl *D) const {
D = getCanonicalDecl(D);
auto *VD = dyn_cast<VarDecl>(D);
const auto *FD = dyn_cast<FieldDecl>(D);
DSAVarData DVar;
- if (isStackEmpty() || Iter == Stack.back().first.rend()) {
+ if (Iter == end()) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// File-scope or namespace-scope variables referenced in called routines
@@ -809,7 +964,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter,
// bound to the current team is shared.
if (isOpenMPTaskingDirective(DVar.DKind)) {
DSAVarData DVarTemp;
- iterator I = Iter, E = Stack.back().first.rend();
+ const_iterator I = Iter, E = end();
do {
++I;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
@@ -841,7 +996,7 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
const Expr *NewDE) {
assert(!isStackEmpty() && "Data sharing attributes stack is empty");
D = getCanonicalDecl(D);
- SharingMapTy &StackElem = Stack.back().first.back();
+ SharingMapTy &StackElem = getTopOfStack();
auto It = StackElem.AlignedMap.find(D);
if (It == StackElem.AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
@@ -855,7 +1010,7 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- SharingMapTy &StackElem = Stack.back().first.back();
+ SharingMapTy &StackElem = getTopOfStack();
StackElem.LCVMap.try_emplace(
D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture));
}
@@ -864,7 +1019,7 @@ const DSAStackTy::LCDeclInfo
DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- const SharingMapTy &StackElem = Stack.back().first.back();
+ const SharingMapTy &StackElem = getTopOfStack();
auto It = StackElem.LCVMap.find(D);
if (It != StackElem.LCVMap.end())
return It->second;
@@ -873,23 +1028,21 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
const DSAStackTy::LCDeclInfo
DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const {
- assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
- "Data-sharing attributes stack is empty");
+ const SharingMapTy *Parent = getSecondOnStackOrNull();
+ assert(Parent && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
- auto It = StackElem.LCVMap.find(D);
- if (It != StackElem.LCVMap.end())
+ auto It = Parent->LCVMap.find(D);
+ if (It != Parent->LCVMap.end())
return It->second;
return {0, nullptr};
}
const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
- assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
- "Data-sharing attributes stack is empty");
- const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
- if (StackElem.LCVMap.size() < I)
+ const SharingMapTy *Parent = getSecondOnStackOrNull();
+ assert(Parent && "Data-sharing attributes stack is empty");
+ if (Parent->LCVMap.size() < I)
return nullptr;
- for (const auto &Pair : StackElem.LCVMap)
+ for (const auto &Pair : Parent->LCVMap)
if (Pair.second.first == I)
return Pair.first;
return nullptr;
@@ -904,8 +1057,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
} else {
- assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
- DSAInfo &Data = Stack.back().first.back().SharingMap[D];
+ DSAInfo &Data = getTopOfStack().SharingMap[D];
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
@@ -920,8 +1072,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
Data.RefExpr.setPointerAndInt(E, IsLastprivate);
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
- DSAInfo &Data =
- Stack.back().first.back().SharingMap[PrivateCopy->getDecl()];
+ DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()];
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
@@ -966,16 +1117,16 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
assert(
- Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ getTopOfStack().SharingMap[D].Attributes == OMPC_reduction &&
"Additional reduction info may be specified only for reduction items.");
- ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D];
+ ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- Stack.back().first.back().Directive == OMPD_taskgroup &&
+ getTopOfStack().Directive == OMPD_taskgroup &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(BOK, SR);
Expr *&TaskgroupReductionRef =
- Stack.back().first.back().TaskgroupReductionRef;
+ getTopOfStack().TaskgroupReductionRef;
if (!TaskgroupReductionRef) {
VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(),
SemaRef.Context.VoidPtrTy, ".task_red.");
@@ -989,16 +1140,16 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
assert(
- Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ getTopOfStack().SharingMap[D].Attributes == OMPC_reduction &&
"Additional reduction info may be specified only for reduction items.");
- ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D];
+ ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- Stack.back().first.back().Directive == OMPD_taskgroup &&
+ getTopOfStack().Directive == OMPD_taskgroup &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(ReductionRef, SR);
Expr *&TaskgroupReductionRef =
- Stack.back().first.back().TaskgroupReductionRef;
+ getTopOfStack().TaskgroupReductionRef;
if (!TaskgroupReductionRef) {
VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(),
SemaRef.Context.VoidPtrTy, ".task_red.");
@@ -1012,11 +1163,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
Expr *&TaskgroupDescriptor) const {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
- if (Stack.back().first.empty())
- return DSAVarData();
- for (iterator I = std::next(Stack.back().first.rbegin(), 1),
- E = Stack.back().first.rend();
- I != E; std::advance(I, 1)) {
+ for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
const DSAInfo &Data = I->SharingMap.lookup(D);
if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
continue;
@@ -1041,11 +1188,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
Expr *&TaskgroupDescriptor) const {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
- if (Stack.back().first.empty())
- return DSAVarData();
- for (iterator I = std::next(Stack.back().first.rbegin(), 1),
- E = Stack.back().first.rend();
- I != E; std::advance(I, 1)) {
+ for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
const DSAInfo &Data = I->SharingMap.lookup(D);
if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
continue;
@@ -1065,21 +1208,17 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
return DSAVarData();
}
-bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const {
+bool DSAStackTy::isOpenMPLocal(VarDecl *D, const_iterator I) const {
D = D->getCanonicalDecl();
- if (!isStackEmpty()) {
- iterator I = Iter, E = Stack.back().first.rend();
- Scope *TopScope = nullptr;
- while (I != E && !isImplicitOrExplicitTaskingRegion(I->Directive) &&
- !isOpenMPTargetExecutionDirective(I->Directive))
- ++I;
- if (I == E)
- return false;
- TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
- Scope *CurScope = getCurScope();
- while (CurScope != TopScope && !CurScope->isDeclScope(D))
- CurScope = CurScope->getParent();
- return CurScope != TopScope;
+ for (const_iterator E = end(); I != E; ++I) {
+ if (isImplicitOrExplicitTaskingRegion(I->Directive) ||
+ isOpenMPTargetExecutionDirective(I->Directive)) {
+ Scope *TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
+ Scope *CurScope = getCurScope();
+ while (CurScope && CurScope != TopScope && !CurScope->isDeclScope(D))
+ CurScope = CurScope->getParent();
+ return CurScope != TopScope;
+ }
}
return false;
}
@@ -1167,15 +1306,14 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
if (SemaRef.getLangOpts().OpenMPCUDAMode && VD &&
VD->isLocalVarDeclOrParm() && !isStackEmpty() &&
!isLoopControlVariable(D).first) {
- iterator IterTarget =
- std::find_if(Stack.back().first.rbegin(), Stack.back().first.rend(),
- [](const SharingMapTy &Data) {
- return isOpenMPTargetExecutionDirective(Data.Directive);
- });
- if (IterTarget != Stack.back().first.rend()) {
- iterator ParentIterTarget = std::next(IterTarget, 1);
- for (iterator Iter = Stack.back().first.rbegin();
- Iter != ParentIterTarget; std::advance(Iter, 1)) {
+ const_iterator IterTarget =
+ std::find_if(begin(), end(), [](const SharingMapTy &Data) {
+ return isOpenMPTargetExecutionDirective(Data.Directive);
+ });
+ if (IterTarget != end()) {
+ const_iterator ParentIterTarget = IterTarget + 1;
+ for (const_iterator Iter = begin();
+ Iter != ParentIterTarget; ++Iter) {
if (isOpenMPLocal(VD, Iter)) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
@@ -1184,7 +1322,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
return DVar;
}
}
- if (!isClauseParsingMode() || IterTarget != Stack.back().first.rbegin()) {
+ if (!isClauseParsingMode() || IterTarget != begin()) {
auto DSAIter = IterTarget->SharingMap.find(D);
if (DSAIter != IterTarget->SharingMap.end() &&
isOpenMPPrivate(DSAIter->getSecond().Attributes)) {
@@ -1192,7 +1330,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
DVar.CKind = OMPC_threadprivate;
return DVar;
}
- iterator End = Stack.back().first.rend();
+ const_iterator End = end();
if (!SemaRef.isOpenMPCapturedByRef(
D, std::distance(ParentIterTarget, End))) {
DVar.RefExpr =
@@ -1216,16 +1354,28 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
// in a Construct, C/C++, predetermined, p.7]
// Variables with static storage duration that are declared in a scope
// inside the construct are shared.
- auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; };
if (VD && VD->isStaticDataMember()) {
- DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent);
- if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
+ // Check for explicitly specified attributes.
+ const_iterator I = begin();
+ const_iterator EndI = end();
+ if (FromParent && I != EndI)
+ ++I;
+ auto It = I->SharingMap.find(D);
+ if (It != I->SharingMap.end()) {
+ const DSAInfo &Data = It->getSecond();
+ DVar.RefExpr = Data.RefExpr.getPointer();
+ DVar.PrivateCopy = Data.PrivateCopy;
+ DVar.CKind = Data.Attributes;
+ DVar.ImplicitDSALoc = I->DefaultAttrLoc;
+ DVar.DKind = I->Directive;
return DVar;
+ }
DVar.CKind = OMPC_shared;
return DVar;
}
+ auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; };
// The predetermined shared attribute for const-qualified types having no
// mutable members was removed after OpenMP 3.1.
if (SemaRef.LangOpts.OpenMP <= 31) {
@@ -1252,10 +1402,10 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
// Explicitly specified attributes and local variables with predetermined
// attributes.
- iterator I = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator I = begin();
+ const_iterator EndI = end();
if (FromParent && I != EndI)
- std::advance(I, 1);
+ ++I;
auto It = I->SharingMap.find(D);
if (It != I->SharingMap.end()) {
const DSAInfo &Data = It->getSecond();
@@ -1272,14 +1422,14 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
bool FromParent) const {
if (isStackEmpty()) {
- iterator I;
+ const_iterator I;
return getDSA(I, D);
}
D = getCanonicalDecl(D);
- iterator StartI = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator StartI = begin();
+ const_iterator EndI = end();
if (FromParent && StartI != EndI)
- std::advance(StartI, 1);
+ ++StartI;
return getDSA(StartI, D);
}
@@ -1291,14 +1441,15 @@ DSAStackTy::hasDSA(ValueDecl *D,
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
- iterator I = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator I = begin();
+ const_iterator EndI = end();
if (FromParent && I != EndI)
- std::advance(I, 1);
- for (; I != EndI; std::advance(I, 1)) {
- if (!DPred(I->Directive) && !isImplicitOrExplicitTaskingRegion(I->Directive))
+ ++I;
+ for (; I != EndI; ++I) {
+ if (!DPred(I->Directive) &&
+ !isImplicitOrExplicitTaskingRegion(I->Directive))
continue;
- iterator NewI = I;
+ const_iterator NewI = I;
DSAVarData DVar = getDSA(NewI, D);
if (I == NewI && CPred(DVar.CKind))
return DVar;
@@ -1313,13 +1464,13 @@ const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
- iterator StartI = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator StartI = begin();
+ const_iterator EndI = end();
if (FromParent && StartI != EndI)
- std::advance(StartI, 1);
+ ++StartI;
if (StartI == EndI || !DPred(StartI->Directive))
return {};
- iterator NewI = StartI;
+ const_iterator NewI = StartI;
DSAVarData DVar = getDSA(NewI, D);
return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData();
}
@@ -1327,23 +1478,19 @@ const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
bool DSAStackTy::hasExplicitDSA(
const ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
unsigned Level, bool NotLastprivate) const {
- if (isStackEmpty())
+ if (getStackSize() <= Level)
return false;
D = getCanonicalDecl(D);
- auto StartI = Stack.back().first.begin();
- auto EndI = Stack.back().first.end();
- if (std::distance(StartI, EndI) <= (int)Level)
- return false;
- std::advance(StartI, Level);
- auto I = StartI->SharingMap.find(D);
- if ((I != StartI->SharingMap.end()) &&
- I->getSecond().RefExpr.getPointer() &&
- CPred(I->getSecond().Attributes) &&
- (!NotLastprivate || !I->getSecond().RefExpr.getInt()))
+ const SharingMapTy &StackElem = getStackElemAtLevel(Level);
+ auto I = StackElem.SharingMap.find(D);
+ if (I != StackElem.SharingMap.end() &&
+ I->getSecond().RefExpr.getPointer() &&
+ CPred(I->getSecond().Attributes) &&
+ (!NotLastprivate || !I->getSecond().RefExpr.getInt()))
return true;
// Check predetermined rules for the loop control variables.
- auto LI = StartI->LCVMap.find(D);
- if (LI != StartI->LCVMap.end())
+ auto LI = StackElem.LCVMap.find(D);
+ if (LI != StackElem.LCVMap.end())
return CPred(OMPC_private);
return false;
}
@@ -1351,14 +1498,10 @@ bool DSAStackTy::hasExplicitDSA(
bool DSAStackTy::hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
unsigned Level) const {
- if (isStackEmpty())
- return false;
- auto StartI = Stack.back().first.begin();
- auto EndI = Stack.back().first.end();
- if (std::distance(StartI, EndI) <= (int)Level)
+ if (getStackSize() <= Level)
return false;
- std::advance(StartI, Level);
- return DPred(StartI->Directive);
+ const SharingMapTy &StackElem = getStackElemAtLevel(Level);
+ return DPred(StackElem.Directive);
}
bool DSAStackTy::hasDirective(
@@ -1367,13 +1510,9 @@ bool DSAStackTy::hasDirective(
DPred,
bool FromParent) const {
// We look only in the enclosing region.
- if (isStackEmpty())
- return false;
- auto StartI = std::next(Stack.back().first.rbegin());
- auto EndI = Stack.back().first.rend();
- if (FromParent && StartI != EndI)
- StartI = std::next(StartI);
- for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ size_t Skip = FromParent ? 2 : 1;
+ for (const_iterator I = begin() + std::min(Skip, getStackSize()), E = end();
+ I != E; ++I) {
if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
return true;
}
@@ -1394,6 +1533,71 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
DSAStack->popFunction(OldFSI);
}
+static bool isOpenMPDeviceDelayedContext(Sema &S) {
+ assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ return !S.isInOpenMPTargetExecutionDirective() &&
+ !S.isInOpenMPDeclareTargetContext();
+}
+
+/// Do we know that we will eventually codegen the given function?
+static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
+ assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ // Templates are emitted when they're instantiated.
+ if (FD->isDependentContext())
+ return false;
+
+ if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
+ FD->getCanonicalDecl()))
+ return true;
+
+ // Otherwise, the function is known-emitted if it's in our set of
+ // known-emitted functions.
+ return S.DeviceKnownEmittedFns.count(FD) > 0;
+}
+
+Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) &&
+ !isKnownEmitted(*this, getCurFunctionDecl()))
+ ? DeviceDiagBuilder::K_Deferred
+ : DeviceDiagBuilder::K_Immediate,
+ Loc, DiagID, getCurFunctionDecl(), *this);
+}
+
+void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+ assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ assert(Callee && "Callee may not be null.");
+ FunctionDecl *Caller = getCurFunctionDecl();
+
+ // If the caller is known-emitted, mark the callee as known-emitted.
+ // Otherwise, mark the call in our call graph so we can traverse it later.
+ if (!isOpenMPDeviceDelayedContext(*this) ||
+ (Caller && isKnownEmitted(*this, Caller)))
+ markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
+ else if (Caller)
+ DeviceCallGraph[Caller].insert({Callee, Loc});
+}
+
+void Sema::checkOpenMPDeviceExpr(const Expr *E) {
+ assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
+ "OpenMP device compilation mode is expected.");
+ QualType Ty = E->getType();
+ if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) ||
+ ((Ty->isFloat128Type() ||
+ (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) &&
+ !Context.getTargetInfo().hasFloat128Type()) ||
+ (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 &&
+ !Context.getTargetInfo().hasInt128Type()))
+ targetDiag(E->getExprLoc(), diag::err_omp_unsupported_type)
+ << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
+ << Context.getTargetInfo().getTriple().str() << E->getSourceRange();
+}
+
bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -1523,12 +1727,10 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
IsByRef =
- ((DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
- !Ty->isAnyPointerType()) ||
- !DSAStack->hasExplicitDSA(
- D,
- [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
- Level, /*NotLastprivate=*/true)) &&
+ !DSAStack->hasExplicitDSA(
+ D,
+ [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
@@ -1565,17 +1767,25 @@ bool Sema::isInOpenMPTargetExecutionDirective() const {
false);
}
-VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
+VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
+ unsigned StopAt) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
+ // If we want to determine whether the variable should be captured from the
+ // perspective of the current capturing scope, and we've already left all the
+ // capturing scopes of the top directive on the stack, check from the
+ // perspective of its parent directive (if any) instead.
+ DSAStackTy::ParentDirectiveScope InParentDirectiveRAII(
+ *DSAStack, CheckScopeInfo && DSAStack->isBodyComplete());
+
// 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.
//
auto *VD = dyn_cast<VarDecl>(D);
- if (VD && !VD->hasLocalStorage()) {
- if (isInOpenMPDeclareTargetContext() &&
- (getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
+ if (VD && !VD->hasLocalStorage() &&
+ (getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
+ if (isInOpenMPDeclareTargetContext()) {
// Try to mark variable as declare target if it is used in capturing
// regions.
if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
@@ -1590,48 +1800,21 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
return VD;
}
}
- // Capture variables captured by reference in lambdas for target-based
- // directives.
- if (VD && !DSAStack->isClauseParsingMode()) {
- if (const auto *RD = VD->getType()
- .getCanonicalType()
- .getNonReferenceType()
- ->getAsCXXRecordDecl()) {
- bool SavedForceCaptureByReferenceInTargetExecutable =
- DSAStack->isForceCaptureByReferenceInTargetExecutable();
- DSAStack->setForceCaptureByReferenceInTargetExecutable(/*V=*/true);
- if (RD->isLambda()) {
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
- FieldDecl *ThisCapture;
- RD->getCaptureFields(Captures, ThisCapture);
- for (const LambdaCapture &LC : RD->captures()) {
- if (LC.getCaptureKind() == LCK_ByRef) {
- VarDecl *VD = LC.getCapturedVar();
- DeclContext *VDC = VD->getDeclContext();
- if (!VDC->Encloses(CurContext))
- continue;
- DSAStackTy::DSAVarData DVarPrivate =
- DSAStack->getTopDSA(VD, /*FromParent=*/false);
- // Do not capture already captured variables.
- if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
- DVarPrivate.CKind == OMPC_unknown &&
- !DSAStack->checkMappableExprComponentListsForDecl(
- D, /*CurrentRegionOnly=*/true,
- [](OMPClauseMappableExprCommon::
- MappableExprComponentListRef,
- OpenMPClauseKind) { return true; }))
- MarkVariableReferenced(LC.getLocation(), LC.getCapturedVar());
- } else if (LC.getCaptureKind() == LCK_This) {
- QualType ThisTy = getCurrentThisType();
- if (!ThisTy.isNull() &&
- Context.typesAreCompatible(ThisTy, ThisCapture->getType()))
- CheckCXXThisCapture(LC.getLocation());
- }
+
+ if (CheckScopeInfo) {
+ bool OpenMPFound = false;
+ for (unsigned I = StopAt + 1; I > 0; --I) {
+ FunctionScopeInfo *FSI = FunctionScopes[I - 1];
+ if(!isa<CapturingScopeInfo>(FSI))
+ return nullptr;
+ if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI))
+ if (RSI->CapRegionKind == CR_OpenMP) {
+ OpenMPFound = true;
+ break;
}
- }
- DSAStack->setForceCaptureByReferenceInTargetExecutable(
- SavedForceCaptureByReferenceInTargetExecutable);
}
+ if (!OpenMPFound)
+ return nullptr;
}
if (DSAStack->getCurrentDirective() != OMPD_unknown &&
@@ -1647,10 +1830,16 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
+ // Threadprivate variables must not be captured.
+ if (isOpenMPThreadPrivate(DVarPrivate.CKind))
+ return nullptr;
+ // The variable is not private or it is the variable in the directive with
+ // default(none) clause and not used in any clause.
DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate,
[](OpenMPDirectiveKind) { return true; },
DSAStack->isClauseParsingMode());
- if (DVarPrivate.CKind != OMPC_unknown)
+ if (DVarPrivate.CKind != OMPC_unknown ||
+ (VD && DSAStack->getDefaultDSA() == DSA_none))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
return nullptr;
@@ -1764,6 +1953,9 @@ void Sema::EndOpenMPClause() {
DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
}
+static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses);
+
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
// OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a lastprivate
@@ -1794,8 +1986,10 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
*this, DE->getExprLoc(), Type.getUnqualifiedType(),
VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE);
ActOnUninitializedDecl(VDPrivate);
- if (VDPrivate->isInvalidDecl())
+ if (VDPrivate->isInvalidDecl()) {
+ PrivateCopies.push_back(nullptr);
continue;
+ }
PrivateCopies.push_back(buildDeclRefExpr(
*this, VDPrivate, DE->getType(), DE->getExprLoc()));
} else {
@@ -1804,11 +1998,12 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
PrivateCopies.push_back(nullptr);
}
}
- // Set initializers to private copies if no errors were found.
- if (PrivateCopies.size() == Clause->varlist_size())
- Clause->setPrivateCopies(PrivateCopies);
+ Clause->setPrivateCopies(PrivateCopies);
}
}
+ // Check allocate clauses.
+ if (!CurContext->isDependentContext())
+ checkAllocateClauses(*this, DSAStack, D->clauses());
}
DSAStack->pop();
@@ -1837,6 +2032,11 @@ public:
}
return false;
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<VarDeclFilterCCC>(*this);
+ }
+
};
class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback {
@@ -1847,19 +2047,25 @@ public:
explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
- if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) {
+ if (ND && ((isa<VarDecl>(ND) && ND->getKind() == Decl::Var) ||
+ isa<FunctionDecl>(ND))) {
return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
SemaRef.getCurScope());
}
return false;
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this);
+ }
};
} // namespace
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id) {
+ const DeclarationNameInfo &Id,
+ OpenMPDirectiveKind Kind) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
@@ -1868,9 +2074,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
VarDecl *VD;
if (!Lookup.isSingleResult()) {
- if (TypoCorrection Corrected = CorrectTypo(
- Id, LookupOrdinaryName, CurScope, nullptr,
- llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) {
+ VarDeclFilterCCC CCC(*this);
+ if (TypoCorrection Corrected =
+ CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC,
+ CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(Lookup.empty()
? diag::err_undeclared_var_use_suggest
@@ -1892,9 +2099,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
- if (!VD->hasGlobalStorage()) {
+ if (Kind == OMPD_threadprivate && !VD->hasGlobalStorage()) {
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal();
+ << getOpenMPDirectiveName(Kind) << !VD->isStaticLocal();
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1911,7 +2118,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
!getCurLexicalContext()->isTranslationUnit()) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1926,7 +2133,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->isStaticDataMember() &&
!CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1942,7 +2149,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
(!getCurLexicalContext()->isFileContext() ||
!getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1953,10 +2160,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
// A threadprivate directive for static block-scope variables must appear
// in the scope of the variable and not in a nested scope.
- if (CanonicalVD->isStaticLocal() && CurScope &&
+ if (CanonicalVD->isLocalVarDecl() && CurScope &&
!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1968,9 +2175,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
- if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) {
+ if (Kind == OMPD_threadprivate && VD->isUsed() &&
+ !DSAStack->isThreadPrivate(VD)) {
Diag(Id.getLoc(), diag::err_omp_var_used)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
return ExprError();
}
@@ -2102,6 +2310,167 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
return D;
}
+static OMPAllocateDeclAttr::AllocatorTypeTy
+getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
+ if (!Allocator)
+ return OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ if (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
+ Allocator->isInstantiationDependent() ||
+ Allocator->containsUnexpandedParameterPack())
+ return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ const Expr *AE = Allocator->IgnoreParenImpCasts();
+ for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
+ const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
+ llvm::FoldingSetNodeID AEId, DAEId;
+ AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
+ DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true);
+ if (AEId == DAEId) {
+ AllocatorKindRes = AllocatorKind;
+ break;
+ }
+ }
+ return AllocatorKindRes;
+}
+
+static bool checkPreviousOMPAllocateAttribute(
+ Sema &S, DSAStackTy *Stack, Expr *RefExpr, VarDecl *VD,
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) {
+ if (!VD->hasAttr<OMPAllocateDeclAttr>())
+ return false;
+ const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
+ Expr *PrevAllocator = A->getAllocator();
+ OMPAllocateDeclAttr::AllocatorTypeTy PrevAllocatorKind =
+ getAllocatorKind(S, Stack, PrevAllocator);
+ bool AllocatorsMatch = AllocatorKind == PrevAllocatorKind;
+ if (AllocatorsMatch &&
+ AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc &&
+ Allocator && PrevAllocator) {
+ const Expr *AE = Allocator->IgnoreParenImpCasts();
+ const Expr *PAE = PrevAllocator->IgnoreParenImpCasts();
+ llvm::FoldingSetNodeID AEId, PAEId;
+ AE->Profile(AEId, S.Context, /*Canonical=*/true);
+ PAE->Profile(PAEId, S.Context, /*Canonical=*/true);
+ AllocatorsMatch = AEId == PAEId;
+ }
+ if (!AllocatorsMatch) {
+ SmallString<256> AllocatorBuffer;
+ llvm::raw_svector_ostream AllocatorStream(AllocatorBuffer);
+ if (Allocator)
+ Allocator->printPretty(AllocatorStream, nullptr, S.getPrintingPolicy());
+ SmallString<256> PrevAllocatorBuffer;
+ llvm::raw_svector_ostream PrevAllocatorStream(PrevAllocatorBuffer);
+ if (PrevAllocator)
+ PrevAllocator->printPretty(PrevAllocatorStream, nullptr,
+ S.getPrintingPolicy());
+
+ SourceLocation AllocatorLoc =
+ Allocator ? Allocator->getExprLoc() : RefExpr->getExprLoc();
+ SourceRange AllocatorRange =
+ Allocator ? Allocator->getSourceRange() : RefExpr->getSourceRange();
+ SourceLocation PrevAllocatorLoc =
+ PrevAllocator ? PrevAllocator->getExprLoc() : A->getLocation();
+ SourceRange PrevAllocatorRange =
+ PrevAllocator ? PrevAllocator->getSourceRange() : A->getRange();
+ S.Diag(AllocatorLoc, diag::warn_omp_used_different_allocator)
+ << (Allocator ? 1 : 0) << AllocatorStream.str()
+ << (PrevAllocator ? 1 : 0) << PrevAllocatorStream.str()
+ << AllocatorRange;
+ S.Diag(PrevAllocatorLoc, diag::note_omp_previous_allocator)
+ << PrevAllocatorRange;
+ return true;
+ }
+ return false;
+}
+
+static void
+applyOMPAllocateAttribute(Sema &S, VarDecl *VD,
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
+ Expr *Allocator, SourceRange SR) {
+ if (VD->hasAttr<OMPAllocateDeclAttr>())
+ return;
+ if (Allocator &&
+ (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
+ Allocator->isInstantiationDependent() ||
+ Allocator->containsUnexpandedParameterPack()))
+ return;
+ auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind,
+ Allocator, SR);
+ VD->addAttr(A);
+ if (ASTMutationListener *ML = S.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPAllocate(VD, A);
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective(
+ SourceLocation Loc, ArrayRef<Expr *> VarList,
+ ArrayRef<OMPClause *> Clauses, DeclContext *Owner) {
+ assert(Clauses.size() <= 1 && "Expected at most one clause.");
+ Expr *Allocator = nullptr;
+ if (Clauses.empty()) {
+ // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions.
+ // allocate directives that appear in a target region must specify an
+ // allocator clause unless a requires directive with the dynamic_allocators
+ // clause is present in the same compilation unit.
+ if (LangOpts.OpenMPIsDevice &&
+ !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
+ targetDiag(Loc, diag::err_expected_allocator_clause);
+ } else {
+ Allocator = cast<OMPAllocatorClause>(Clauses.back())->getAllocator();
+ }
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
+ getAllocatorKind(*this, DSAStack, Allocator);
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ auto *DE = cast<DeclRefExpr>(RefExpr);
+ auto *VD = cast<VarDecl>(DE->getDecl());
+
+ // Check if this is a TLS variable or global register.
+ if (VD->getTLSKind() != VarDecl::TLS_None ||
+ VD->hasAttr<OMPThreadPrivateDeclAttr>() ||
+ (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() &&
+ !VD->isLocalVarDecl()))
+ continue;
+
+ // If the used several times in the allocate directive, the same allocator
+ // must be used.
+ if (checkPreviousOMPAllocateAttribute(*this, DSAStack, RefExpr, VD,
+ AllocatorKind, Allocator))
+ continue;
+
+ // OpenMP, 2.11.3 allocate Directive, Restrictions, C / C++
+ // If a list item has a static storage type, the allocator expression in the
+ // allocator clause must be a constant expression that evaluates to one of
+ // the predefined memory allocator values.
+ if (Allocator && VD->hasGlobalStorage()) {
+ if (AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc) {
+ Diag(Allocator->getExprLoc(),
+ diag::err_omp_expected_predefined_allocator)
+ << Allocator->getSourceRange();
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ }
+
+ Vars.push_back(RefExpr);
+ applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator,
+ DE->getSourceRange());
+ }
+ if (Vars.empty())
+ return nullptr;
+ if (!Owner)
+ Owner = getCurLexicalContext();
+ auto *D = OMPAllocateDecl::Create(Context, Owner, Loc, Vars, Clauses);
+ D->setAccess(AS_public);
+ Owner->addDecl(D);
+ return DeclGroupPtrTy::make(DeclGroupRef(D));
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
@@ -2120,6 +2489,27 @@ Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc,
OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
+ /// For target specific clauses, the requires directive cannot be
+ /// specified after the handling of any of the target regions in the
+ /// current compilation unit.
+ ArrayRef<SourceLocation> TargetLocations =
+ DSAStack->getEncounteredTargetLocs();
+ if (!TargetLocations.empty()) {
+ for (const OMPClause *CNew : ClauseList) {
+ // Check if any of the requires clauses affect target regions.
+ if (isa<OMPUnifiedSharedMemoryClause>(CNew) ||
+ isa<OMPUnifiedAddressClause>(CNew) ||
+ isa<OMPReverseOffloadClause>(CNew) ||
+ isa<OMPDynamicAllocatorsClause>(CNew)) {
+ Diag(Loc, diag::err_omp_target_before_requires)
+ << getOpenMPClauseName(CNew->getClauseKind());
+ for (SourceLocation TargetLoc : TargetLocations) {
+ Diag(TargetLoc, diag::note_omp_requires_encountered_target);
+ }
+ }
+ }
+ }
+
if (!DSAStack->hasDuplicateRequiresClause(ClauseList))
return OMPRequiresDecl::Create(Context, getCurLexicalContext(), Loc,
ClauseList);
@@ -2198,24 +2588,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
// Check implicitly captured variables.
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
return;
- for (const CapturedStmt::Capture &Cap :
- S->getInnermostCapturedStmt()->captures()) {
- if (!Cap.capturesVariable())
- continue;
- VarDecl *VD = Cap.getCapturedVar();
- // Do not try to map the variable if it or its sub-component was mapped
- // already.
- if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
- Stack->checkMappableExprComponentListsForDecl(
- VD, /*CurrentRegionOnly=*/true,
- [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
- OpenMPClauseKind) { return true; }))
- continue;
- DeclRefExpr *DRE = buildDeclRefExpr(
- SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context),
- Cap.getLocation(), /*RefersToCapture=*/true);
- Visit(DRE);
- }
+ visitSubCaptures(S->getInnermostCapturedStmt());
}
public:
@@ -2224,9 +2597,20 @@ public:
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ // Check the datasharing rules for the expressions in the clauses.
+ if (!CS) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
+ if (!CED->hasAttr<OMPCaptureNoInitAttr>()) {
+ Visit(CED->getInit());
+ return;
+ }
+ } else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(VD))
+ // Do not analyze internal variables and do not enclose them into
+ // implicit clauses.
+ return;
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->hasLocalStorage() && !CS->capturesVariable(VD))
+ if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD))
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
@@ -2237,8 +2621,9 @@ public:
// Skip internally declared static variables.
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) &&
- (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
+ if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
+ (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
+ !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
return;
SourceLocation ELoc = E->getExprLoc();
@@ -2315,8 +2700,18 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
- !Stack->isLoopControlVariable(VD).first)
+ !Stack->isLoopControlVariable(VD).first) {
ImplicitFirstprivate.push_back(E);
+ return;
+ }
+
+ // Store implicitly used globals with declare target link for parent
+ // target.
+ if (!isOpenMPTargetExecutionDirective(DKind) && Res &&
+ *Res == OMPDeclareTargetDeclAttr::MT_Link) {
+ Stack->addToParentTargetRegionLinkGlobals(E);
+ return;
+ }
}
}
void VisitMemberExpr(MemberExpr *E) {
@@ -2464,6 +2859,25 @@ public:
}
}
+ void visitSubCaptures(CapturedStmt *S) {
+ for (const CapturedStmt::Capture &Cap : S->captures()) {
+ if (!Cap.capturesVariable() && !Cap.capturesVariableByCopy())
+ continue;
+ VarDecl *VD = Cap.getCapturedVar();
+ // Do not try to map the variable if it or its sub-component was mapped
+ // already.
+ if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
+ Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind) { return true; }))
+ continue;
+ DeclRefExpr *DRE = buildDeclRefExpr(
+ SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context),
+ Cap.getLocation(), /*RefersToCapture=*/true);
+ Visit(DRE);
+ }
+ }
bool isErrorFound() const { return ErrorFound; }
ArrayRef<Expr *> getImplicitFirstprivate() const {
return ImplicitFirstprivate;
@@ -2474,7 +2888,13 @@ public:
}
DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
- : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {}
+ : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {
+ // Process declare target link variables for the target directives.
+ if (isOpenMPTargetExecutionDirective(S->getCurrentDirective())) {
+ for (DeclRefExpr *E : Stack->getLinkGlobals())
+ Visit(E);
+ }
+ }
};
} // namespace
@@ -2802,6 +3222,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
@@ -2809,6 +3230,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_cancel:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -2915,6 +3337,46 @@ public:
};
} // namespace
+void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
+ // Capture variables captured by reference in lambdas for target-based
+ // directives.
+ if (!CurContext->isDependentContext() &&
+ (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) ||
+ isOpenMPTargetDataManagementDirective(
+ DSAStack->getCurrentDirective()))) {
+ QualType Type = V->getType();
+ if (const auto *RD = Type.getCanonicalType()
+ .getNonReferenceType()
+ ->getAsCXXRecordDecl()) {
+ bool SavedForceCaptureByReferenceInTargetExecutable =
+ DSAStack->isForceCaptureByReferenceInTargetExecutable();
+ DSAStack->setForceCaptureByReferenceInTargetExecutable(
+ /*V=*/true);
+ if (RD->isLambda()) {
+ llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+ FieldDecl *ThisCapture;
+ RD->getCaptureFields(Captures, ThisCapture);
+ for (const LambdaCapture &LC : RD->captures()) {
+ if (LC.getCaptureKind() == LCK_ByRef) {
+ VarDecl *VD = LC.getCapturedVar();
+ DeclContext *VDC = VD->getDeclContext();
+ if (!VDC->Encloses(CurContext))
+ continue;
+ MarkVariableReferenced(LC.getLocation(), VD);
+ } else if (LC.getCaptureKind() == LCK_This) {
+ QualType ThisTy = getCurrentThisType();
+ if (!ThisTy.isNull() &&
+ Context.typesAreCompatible(ThisTy, ThisCapture->getType()))
+ CheckCXXThisCapture(LC.getLocation());
+ }
+ }
+ }
+ DSAStack->setForceCaptureByReferenceInTargetExecutable(
+ SavedForceCaptureByReferenceInTargetExecutable);
+ }
+ }
+}
+
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
bool ErrorFound = false;
@@ -3004,6 +3466,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
return StmtError();
}
StmtResult SR = S;
+ unsigned CompletedRegions = 0;
for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(CaptureRegions)) {
// Mark all variables in private list clauses as used in inner region.
// Required for proper codegen of combined directives.
@@ -3025,6 +3488,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
}
}
+ if (++CompletedRegions == CaptureRegions.size())
+ DSAStack->setBodyComplete();
SR = ActOnCapturedRegionEnd(SR.get());
}
return SR;
@@ -3346,6 +3811,169 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
return ErrorFound;
}
+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)) {
+ Expr *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)) {
+ Expr *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(
+ getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
+}
+
+static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses) {
+ assert(!S.CurContext->isDependentContext() &&
+ "Expected non-dependent context.");
+ auto AllocateRange =
+ llvm::make_filter_range(Clauses, OMPAllocateClause::classof);
+ llvm::DenseMap<CanonicalDeclPtr<Decl>, CanonicalDeclPtr<VarDecl>>
+ DeclToCopy;
+ auto PrivateRange = llvm::make_filter_range(Clauses, [](const OMPClause *C) {
+ return isOpenMPPrivate(C->getClauseKind());
+ });
+ for (OMPClause *Cl : PrivateRange) {
+ MutableArrayRef<Expr *>::iterator I, It, Et;
+ if (Cl->getClauseKind() == OMPC_private) {
+ auto *PC = cast<OMPPrivateClause>(Cl);
+ I = PC->private_copies().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_firstprivate) {
+ auto *PC = cast<OMPFirstprivateClause>(Cl);
+ I = PC->private_copies().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_lastprivate) {
+ auto *PC = cast<OMPLastprivateClause>(Cl);
+ I = PC->private_copies().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_linear) {
+ auto *PC = cast<OMPLinearClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_reduction) {
+ auto *PC = cast<OMPReductionClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_task_reduction) {
+ auto *PC = cast<OMPTaskReductionClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_in_reduction) {
+ auto *PC = cast<OMPInReductionClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else {
+ llvm_unreachable("Expected private clause.");
+ }
+ for (Expr *E : llvm::make_range(It, Et)) {
+ if (!*I) {
+ ++I;
+ continue;
+ }
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = E;
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ DeclToCopy.try_emplace(Res.first,
+ cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()));
+ ++I;
+ }
+ }
+ for (OMPClause *C : AllocateRange) {
+ auto *AC = cast<OMPAllocateClause>(C);
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
+ getAllocatorKind(S, Stack, AC->getAllocator());
+ // OpenMP, 2.11.4 allocate Clause, Restrictions.
+ // For task, taskloop or target directives, allocation requests to memory
+ // allocators with the trait access set to thread result in unspecified
+ // behavior.
+ if (AllocatorKind == OMPAllocateDeclAttr::OMPThreadMemAlloc &&
+ (isOpenMPTaskingDirective(Stack->getCurrentDirective()) ||
+ isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()))) {
+ S.Diag(AC->getAllocator()->getExprLoc(),
+ diag::warn_omp_allocate_thread_on_task_target_directive)
+ << getOpenMPDirectiveName(Stack->getCurrentDirective());
+ }
+ for (Expr *E : AC->varlists()) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = E;
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange);
+ ValueDecl *VD = Res.first;
+ DSAStackTy::DSAVarData Data = Stack->getTopDSA(VD, /*FromParent=*/false);
+ if (!isOpenMPPrivate(Data.CKind)) {
+ S.Diag(E->getExprLoc(),
+ diag::err_omp_expected_private_copy_for_allocate);
+ continue;
+ }
+ VarDecl *PrivateVD = DeclToCopy[VD];
+ if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD,
+ AllocatorKind, AC->getAllocator()))
+ continue;
+ applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(),
+ E->getSourceRange());
+ }
+ }
+}
+
StmtResult Sema::ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
@@ -3371,6 +3999,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
while (--ThisCaptureLevel >= 0)
S = cast<CapturedStmt>(S)->getCapturedStmt();
DSAChecker.Visit(S);
+ if (!isOpenMPTargetDataManagementDirective(Kind) &&
+ !isOpenMPTaskingDirective(Kind)) {
+ // Visit subcaptures to generate implicit clauses for captured vars.
+ auto *CS = cast<CapturedStmt>(AStmt);
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, Kind);
+ // Ignore outer tasking regions for target directives.
+ if (CaptureRegions.size() > 1 && CaptureRegions.front() == OMPD_task)
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ DSAChecker.visitSubCaptures(CS);
+ }
if (DSAChecker.isErrorFound())
return StmtError();
// Generate list of implicitly defined firstprivate variables.
@@ -3401,11 +4040,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
}
}
if (!ImplicitMaps.empty()) {
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperId;
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- llvm::None, llvm::None, OMPC_MAP_tofrom,
- /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
- ImplicitMaps, SourceLocation(), SourceLocation(),
- SourceLocation())) {
+ llvm::None, llvm::None, MapperIdScopeSpec, MapperId,
+ OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(),
+ SourceLocation(), ImplicitMaps, OMPVarListLocTy())) {
ClausesWithImplicit.emplace_back(Implicit);
ErrorFound |=
cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
@@ -3656,7 +4296,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_requires:
llvm_unreachable("OpenMP Directive is not allowed");
@@ -3664,11 +4306,99 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
llvm_unreachable("Unknown OpenMP directive");
}
+ ErrorFound = Res.isInvalid() || ErrorFound;
+
+ // Check variables in the clauses if default(none) was specified.
+ if (DSAStack->getDefaultDSA() == DSA_none) {
+ DSAAttrChecker DSAChecker(DSAStack, *this, nullptr);
+ for (OMPClause *C : Clauses) {
+ switch (C->getClauseKind()) {
+ case OMPC_num_threads:
+ case OMPC_dist_schedule:
+ // Do not analyse if no parent teams directive.
+ if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()))
+ break;
+ continue;
+ case OMPC_if:
+ if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) &&
+ cast<OMPIfClause>(C)->getNameModifier() != OMPD_target)
+ break;
+ continue;
+ case OMPC_schedule:
+ break;
+ case OMPC_ordered:
+ case OMPC_device:
+ case OMPC_num_teams:
+ case OMPC_thread_limit:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_hint:
+ case OMPC_collapse:
+ case OMPC_safelen:
+ case OMPC_simdlen:
+ case OMPC_final:
+ case OMPC_default:
+ case OMPC_proc_bind:
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_lastprivate:
+ case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_allocate:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
+ case OMPC_depend:
+ case OMPC_threads:
+ case OMPC_simd:
+ case OMPC_map:
+ case OMPC_nogroup:
+ case OMPC_defaultmap:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
+ continue;
+ case OMPC_allocator:
+ case OMPC_flush:
+ case OMPC_threadprivate:
+ case OMPC_uniform:
+ case OMPC_unknown:
+ case OMPC_unified_address:
+ case OMPC_unified_shared_memory:
+ case OMPC_reverse_offload:
+ case OMPC_dynamic_allocators:
+ case OMPC_atomic_default_mem_order:
+ llvm_unreachable("Unexpected clause");
+ }
+ for (Stmt *CC : C->children()) {
+ if (CC)
+ DSAChecker.Visit(CC);
+ }
+ }
+ for (auto &P : DSAChecker.getVarsWithInheritedDSA())
+ VarsWithInheritedDSA[P.getFirst()] = P.getSecond();
+ }
for (const auto &P : VarsWithInheritedDSA) {
+ if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst()))
+ continue;
+ ErrorFound = true;
Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
<< P.first << P.second->getSourceRange();
+ Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
}
- ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound;
if (!AllowedNameModifiers.empty())
ErrorFound = checkIfClauses(*this, Kind, Clauses, AllowedNameModifiers) ||
@@ -3676,6 +4406,23 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (ErrorFound)
return StmtError();
+
+ if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) {
+ Res.getAs<OMPExecutableDirective>()
+ ->getStructuredBlock()
+ ->setIsOMPStructuredBlock(true);
+ }
+
+ if (!CurContext->isDependentContext() &&
+ isOpenMPTargetExecutionDirective(Kind) &&
+ !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
+ DSAStack->hasRequiresDeclWithClause<OMPUnifiedAddressClause>() ||
+ DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>() ||
+ DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())) {
+ // Register target to DSA Stack.
+ DSAStack->addTargetDirLocation(StartLoc);
+ }
+
return Res;
}
@@ -3953,6 +4700,8 @@ namespace {
class OpenMPIterationSpaceChecker {
/// Reference to Sema.
Sema &SemaRef;
+ /// Data-sharing stack.
+ DSAStackTy &Stack;
/// A location for diagnostics (when there is no some better location).
SourceLocation DefaultLoc;
/// A location for diagnostics (when increment is not compatible).
@@ -3984,10 +4733,22 @@ class OpenMPIterationSpaceChecker {
bool TestIsStrictOp = false;
/// This flag is true when step is subtracted on each iteration.
bool SubtractStep = false;
+ /// The outer loop counter this loop depends on (if any).
+ const ValueDecl *DepDecl = nullptr;
+ /// Contains number of loop (starts from 1) on which loop counter init
+ /// expression of this loop depends on.
+ Optional<unsigned> InitDependOnLC;
+ /// Contains number of loop (starts from 1) on which loop counter condition
+ /// expression of this loop depends on.
+ Optional<unsigned> CondDependOnLC;
+ /// Checks if the provide statement depends on the loop counter.
+ Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
public:
- OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
- : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {}
+ OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack,
+ SourceLocation DefaultLoc)
+ : SemaRef(SemaRef), Stack(Stack), DefaultLoc(DefaultLoc),
+ ConditionLoc(DefaultLoc) {}
/// Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
bool checkAndSetInit(Stmt *S, bool EmitDiags = true);
@@ -4009,6 +4770,8 @@ public:
SourceRange getIncrementSrcRange() const { return IncrementSrcRange; }
/// True if the step should be subtracted.
bool shouldSubtractStep() const { return SubtractStep; }
+ /// True, if the compare operator is strict (<, > or !=).
+ bool isStrictTestOp() const { return TestIsStrictOp; }
/// Build the expression to calculate the number of iterations.
Expr *buildNumIterations(
Scope *S, const bool LimitedType,
@@ -4043,7 +4806,8 @@ private:
/// expression.
bool checkAndSetIncRHS(Expr *RHS);
/// Helper to set loop counter variable and its initializer.
- bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB);
+ bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB,
+ bool EmitDiags);
/// Helper to set upper bound.
bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL);
@@ -4063,7 +4827,7 @@ bool OpenMPIterationSpaceChecker::dependent() const {
bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
Expr *NewLCRefExpr,
- Expr *NewLB) {
+ Expr *NewLB, bool EmitDiags) {
// State consistency checking to ensure correct usage.
assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr &&
UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
@@ -4078,10 +4842,13 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
NewLB = CE->getArg(0)->IgnoreParenImpCasts();
LB = NewLB;
+ if (EmitDiags)
+ InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true);
return false;
}
-bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp,
+bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB,
+ llvm::Optional<bool> LessOp,
bool StrictOp, SourceRange SR,
SourceLocation SL) {
// State consistency checking to ensure correct usage.
@@ -4095,6 +4862,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp
TestIsStrictOp = StrictOp;
ConditionSrcRange = SR;
ConditionLoc = SL;
+ CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false);
return false;
}
@@ -4160,6 +4928,110 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
return false;
}
+namespace {
+/// Checker for the non-rectangular loops. Checks if the initializer or
+/// condition expression references loop counter variable.
+class LoopCounterRefChecker final
+ : public ConstStmtVisitor<LoopCounterRefChecker, bool> {
+ Sema &SemaRef;
+ DSAStackTy &Stack;
+ const ValueDecl *CurLCDecl = nullptr;
+ const ValueDecl *DepDecl = nullptr;
+ const ValueDecl *PrevDepDecl = nullptr;
+ bool IsInitializer = true;
+ unsigned BaseLoopId = 0;
+ bool checkDecl(const Expr *E, const ValueDecl *VD) {
+ if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) {
+ SemaRef.Diag(E->getExprLoc(), diag::err_omp_stmt_depends_on_loop_counter)
+ << (IsInitializer ? 0 : 1);
+ return false;
+ }
+ const auto &&Data = Stack.isLoopControlVariable(VD);
+ // OpenMP, 2.9.1 Canonical Loop Form, Restrictions.
+ // The type of the loop iterator on which we depend may not have a random
+ // access iterator type.
+ if (Data.first && VD->getType()->isRecordType()) {
+ SmallString<128> Name;
+ llvm::raw_svector_ostream OS(Name);
+ VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(),
+ /*Qualified=*/true);
+ SemaRef.Diag(E->getExprLoc(),
+ diag::err_omp_wrong_dependency_iterator_type)
+ << OS.str();
+ SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD;
+ return false;
+ }
+ if (Data.first &&
+ (DepDecl || (PrevDepDecl &&
+ getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) {
+ if (!DepDecl && PrevDepDecl)
+ DepDecl = PrevDepDecl;
+ SmallString<128> Name;
+ llvm::raw_svector_ostream OS(Name);
+ DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(),
+ /*Qualified=*/true);
+ SemaRef.Diag(E->getExprLoc(),
+ diag::err_omp_invariant_or_linear_dependency)
+ << OS.str();
+ return false;
+ }
+ if (Data.first) {
+ DepDecl = VD;
+ BaseLoopId = Data.first;
+ }
+ return Data.first;
+ }
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ const ValueDecl *VD = E->getDecl();
+ if (isa<VarDecl>(VD))
+ return checkDecl(E, VD);
+ return false;
+ }
+ bool VisitMemberExpr(const MemberExpr *E) {
+ if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) {
+ const ValueDecl *VD = E->getMemberDecl();
+ if (isa<VarDecl>(VD) || isa<FieldDecl>(VD))
+ return checkDecl(E, VD);
+ }
+ return false;
+ }
+ bool VisitStmt(const Stmt *S) {
+ bool Res = true;
+ for (const Stmt *Child : S->children())
+ Res = Child && Visit(Child) && Res;
+ return Res;
+ }
+ explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
+ const ValueDecl *CurLCDecl, bool IsInitializer,
+ const ValueDecl *PrevDepDecl = nullptr)
+ : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl),
+ PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer) {}
+ unsigned getBaseLoopId() const {
+ assert(CurLCDecl && "Expected loop dependency.");
+ return BaseLoopId;
+ }
+ const ValueDecl *getDepDecl() const {
+ assert(CurLCDecl && "Expected loop dependency.");
+ return DepDecl;
+ }
+};
+} // namespace
+
+Optional<unsigned>
+OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
+ bool IsInitializer) {
+ // Check for the non-rectangular loops.
+ LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer,
+ DepDecl);
+ if (LoopStmtChecker.Visit(S)) {
+ DepDecl = LoopStmtChecker.getDepDecl();
+ return LoopStmtChecker.getBaseLoopId();
+ }
+ return llvm::None;
+}
+
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
// Check init-expr for canonical loop form and save loop counter
// variable - #Var and its initialization value - #LB.
@@ -4188,13 +5060,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
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());
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
+ return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags);
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
- return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
}
}
} else if (auto *DS = dyn_cast<DeclStmt>(S)) {
@@ -4211,7 +5085,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
buildDeclRefExpr(SemaRef, Var,
Var->getType().getNonReferenceType(),
DS->getBeginLoc()),
- Var->getInit());
+ Var->getInit(), EmitDiags);
}
}
}
@@ -4221,13 +5095,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
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));
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
+ return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags);
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
- return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
}
}
}
@@ -4581,7 +5457,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
/*AllowExplicit=*/true);
}
SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
- // Otherwise use original loop conditon and evaluate it in runtime.
+ // Otherwise use original loop condition and evaluate it in runtime.
return CondExpr.isUsable() ? CondExpr.get() : Cond;
}
@@ -4602,8 +5478,7 @@ DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar(
Captures.insert(std::make_pair(LCRef, Ref));
return Ref;
}
- return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(),
- DefaultLoc);
+ return cast<DeclRefExpr>(LCRef);
}
Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const {
@@ -4648,10 +5523,12 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
// Upper - Lower
- Expr *Upper =
- TestIsLessOp.getValue() ? Cnt : tryBuildCapture(SemaRef, UB, Captures).get();
- Expr *Lower =
- TestIsLessOp.getValue() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
+ Expr *Upper = TestIsLessOp.getValue()
+ ? Cnt
+ : tryBuildCapture(SemaRef, UB, Captures).get();
+ Expr *Lower = TestIsLessOp.getValue()
+ ? tryBuildCapture(SemaRef, LB, Captures).get()
+ : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -4687,6 +5564,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
/// Iteration space of a single for loop.
struct LoopIterationSpace final {
+ /// True if the condition operator is the strict compare operator (<, > or
+ /// !=).
+ bool IsStrictCompare = false;
/// Condition of the loop.
Expr *PreCond = nullptr;
/// This expression calculates the number of iterations in the loop.
@@ -4720,7 +5600,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (AssociatedLoops > 0 &&
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
DSAStack->loopStart();
- OpenMPIterationSpaceChecker ISC(*this, ForLoc);
+ OpenMPIterationSpaceChecker ISC(*this, *DSAStack, ForLoc);
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
@@ -4786,7 +5666,7 @@ static bool checkOpenMPIterationSpace(
}
assert(For->getBody());
- OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
+ OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
// Check init.
Stmt *Init = For->getInit();
@@ -4840,12 +5720,14 @@ static bool checkOpenMPIterationSpace(
? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
: OMPC_private;
if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != PredeterminedCKind) ||
+ DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
+ (SemaRef.getLangOpts().OpenMP <= 45 ||
+ (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) ||
((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)) {
+ (DVar.CKind != OMPC_private || DVar.RefExpr)) {
SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
<< getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(PredeterminedCKind);
@@ -4859,10 +5741,7 @@ static bool checkOpenMPIterationSpace(
// 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);
+ DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
}
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
@@ -4893,6 +5772,7 @@ static bool checkOpenMPIterationSpace(
ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange();
ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange();
ResultIterSpace.Subtract = ISC.shouldSubtractStep();
+ ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp();
HasErrors |= (ResultIterSpace.PreCond == nullptr ||
ResultIterSpace.NumIterations == nullptr ||
@@ -5117,14 +5997,21 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (CollapseLoopCountExpr) {
// Found 'collapse' clause - calculate collapse number.
Expr::EvalResult Result;
- if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
+ if (!CollapseLoopCountExpr->isValueDependent() &&
+ CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) {
NestedLoopCount = Result.Val.getInt().getLimitedValue();
+ } else {
+ Built.clear(/*Size=*/1);
+ return 1;
+ }
}
unsigned OrderedLoopCount = 1;
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
Expr::EvalResult EVResult;
- if (OrderedLoopCountExpr->EvaluateAsInt(EVResult, SemaRef.getASTContext())) {
+ if (!OrderedLoopCountExpr->isValueDependent() &&
+ OrderedLoopCountExpr->EvaluateAsInt(EVResult,
+ SemaRef.getASTContext())) {
llvm::APSInt Result = EVResult.Val.getInt();
if (Result.getLimitedValue() < NestedLoopCount) {
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
@@ -5135,13 +6022,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
<< CollapseLoopCountExpr->getSourceRange();
}
OrderedLoopCount = Result.getLimitedValue();
+ } else {
+ Built.clear(/*Size=*/1);
+ return 1;
}
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- SmallVector<LoopIterationSpace, 4> IterSpaces;
- IterSpaces.resize(std::max(OrderedLoopCount, NestedLoopCount));
+ SmallVector<LoopIterationSpace, 4> IterSpaces(
+ std::max(OrderedLoopCount, NestedLoopCount));
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
@@ -5447,25 +6337,55 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
}
}
- // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
+ bool UseStrictCompare =
+ RealVType->hasUnsignedIntegerRepresentation() &&
+ llvm::all_of(IterSpaces, [](const LoopIterationSpace &LIS) {
+ return LIS.IsStrictCompare;
+ });
+ // Loop condition (IV < NumIterations) or (IV <= UB or IV < UB + 1 (for
+ // unsigned IV)) for worksharing loops.
SourceLocation CondLoc = AStmt->getBeginLoc();
+ Expr *BoundUB = UB.get();
+ if (UseStrictCompare) {
+ BoundUB =
+ SemaRef
+ .BuildBinOp(CurScope, CondLoc, BO_Add, BoundUB,
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get())
+ .get();
+ BoundUB =
+ SemaRef.ActOnFinishFullExpr(BoundUB, /*DiscardedValue*/ false).get();
+ }
ExprResult Cond =
(isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind))
- ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
+ ? SemaRef.BuildBinOp(CurScope, CondLoc,
+ UseStrictCompare ? BO_LT : BO_LE, IV.get(),
+ BoundUB)
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
NumIterations.get());
ExprResult CombDistCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
- CombDistCond =
- SemaRef.BuildBinOp(
- CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get());
+ CombDistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
+ NumIterations.get());
}
ExprResult CombCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ Expr *BoundCombUB = CombUB.get();
+ if (UseStrictCompare) {
+ BoundCombUB =
+ SemaRef
+ .BuildBinOp(
+ CurScope, CondLoc, BO_Add, BoundCombUB,
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get())
+ .get();
+ BoundCombUB =
+ SemaRef.ActOnFinishFullExpr(BoundCombUB, /*DiscardedValue*/ false)
+ .get();
+ }
CombCond =
- SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get());
+ SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE,
+ IV.get(), BoundCombUB);
}
// Loop increment (IV = IV + 1)
SourceLocation IncLoc = AStmt->getBeginLoc();
@@ -5542,7 +6462,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
SourceLocation DistIncLoc = AStmt->getBeginLoc();
ExprResult DistCond, DistInc, PrevEUB, ParForInDistCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
- DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get());
+ DistCond = SemaRef.BuildBinOp(
+ CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, IV.get(), BoundUB);
assert(DistCond.isUsable() && "distribute cond expr was not built");
DistInc =
@@ -5566,10 +6487,24 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
PrevEUB =
SemaRef.ActOnFinishFullExpr(PrevEUB.get(), /*DiscardedValue*/ false);
- // Build IV <= PrevUB to be used in parallel for is in combination with
- // a distribute directive with schedule(static, 1)
+ // Build IV <= PrevUB or IV < PrevUB + 1 for unsigned IV to be used in
+ // parallel for is in combination with a distribute directive with
+ // schedule(static, 1)
+ Expr *BoundPrevUB = PrevUB.get();
+ if (UseStrictCompare) {
+ BoundPrevUB =
+ SemaRef
+ .BuildBinOp(
+ CurScope, CondLoc, BO_Add, BoundPrevUB,
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get())
+ .get();
+ BoundPrevUB =
+ SemaRef.ActOnFinishFullExpr(BoundPrevUB, /*DiscardedValue*/ false)
+ .get();
+ }
ParForInDistCond =
- SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), PrevUB.get());
+ SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE,
+ IV.get(), BoundPrevUB);
}
// Build updates and final values of the loop counters.
@@ -7015,7 +7950,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
auto I = CS->body_begin();
while (I != CS->body_end()) {
const auto *OED = dyn_cast<OMPExecutableDirective>(*I);
- if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) {
+ if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind()) ||
+ OMPTeamsFound) {
+
OMPTeamsFound = false;
break;
}
@@ -8235,6 +9172,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_simdlen:
Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_allocator:
+ Res = ActOnOpenMPAllocatorClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_collapse:
Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -8281,6 +9221,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -8365,12 +9306,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
// Do not capture if-clause expressions.
break;
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8431,12 +9374,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8498,12 +9443,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8562,12 +9509,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8627,12 +9576,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8691,12 +9642,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8754,12 +9707,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -8793,6 +9748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_private:
case OMPC_shared:
@@ -8804,6 +9760,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -9042,6 +9999,71 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc,
OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc);
}
+/// Tries to find omp_allocator_handle_t type.
+static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
+ DSAStackTy *Stack) {
+ QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT();
+ if (!OMPAllocatorHandleT.isNull())
+ return true;
+ // Build the predefined allocator expressions.
+ bool ErrorFound = false;
+ for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
+ StringRef Allocator =
+ OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind);
+ DeclarationName AllocatorName = &S.getASTContext().Idents.get(Allocator);
+ auto *VD = dyn_cast_or_null<ValueDecl>(
+ S.LookupSingleName(S.TUScope, AllocatorName, Loc, Sema::LookupAnyName));
+ if (!VD) {
+ ErrorFound = true;
+ break;
+ }
+ QualType AllocatorType =
+ VD->getType().getNonLValueExprType(S.getASTContext());
+ ExprResult Res = S.BuildDeclRefExpr(VD, AllocatorType, VK_LValue, Loc);
+ if (!Res.isUsable()) {
+ ErrorFound = true;
+ break;
+ }
+ if (OMPAllocatorHandleT.isNull())
+ OMPAllocatorHandleT = AllocatorType;
+ if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) {
+ ErrorFound = true;
+ break;
+ }
+ Stack->setAllocator(AllocatorKind, Res.get());
+ }
+ if (ErrorFound) {
+ S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found);
+ return false;
+ }
+ OMPAllocatorHandleT.addConst();
+ Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT);
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPAllocatorClause(Expr *A, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.11.3, allocate Directive, Description]
+ // allocator is an expression of omp_allocator_handle_t type.
+ if (!findOMPAllocatorHandleT(*this, A->getExprLoc(), DSAStack))
+ return nullptr;
+
+ ExprResult Allocator = DefaultLvalueConversion(A);
+ if (Allocator.isInvalid())
+ return nullptr;
+ Allocator = PerformImplicitConversion(Allocator.get(),
+ DSAStack->getOMPAllocatorHandleT(),
+ Sema::AA_Initializing,
+ /*AllowExplicit=*/true);
+ if (Allocator.isInvalid())
+ return nullptr;
+ return new (Context)
+ OMPAllocatorClause(Allocator.get(), StartLoc, LParenLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -9109,6 +10131,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
@@ -9127,6 +10150,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -9285,6 +10309,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
@@ -9304,6 +10329,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -9505,6 +10531,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
@@ -9521,6 +10548,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_default:
case OMPC_proc_bind:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_depend:
case OMPC_device:
@@ -9623,14 +10651,16 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc,
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
- SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
- SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind,
+ const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
+ CXXScopeSpec &ReductionOrMapperIdScopeSpec,
+ DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind,
OpenMPLinearClauseKind LinKind,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc,
- OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
- SourceLocation DepLinMapLoc) {
+ ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType,
+ bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) {
+ SourceLocation StartLoc = Locs.StartLoc;
+ SourceLocation LParenLoc = Locs.LParenLoc;
+ SourceLocation EndLoc = Locs.EndLoc;
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_private:
@@ -9647,17 +10677,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
break;
case OMPC_reduction:
Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionIdScopeSpec, ReductionId);
+ EndLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId);
break;
case OMPC_task_reduction:
Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionIdScopeSpec,
- ReductionId);
+ EndLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId);
break;
case OMPC_in_reduction:
- Res =
- ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionIdScopeSpec, ReductionId);
+ Res = ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId);
break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
@@ -9681,27 +10712,35 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
- Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, MapType,
- IsMapTypeImplicit, DepLinMapLoc, ColonLoc,
- VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc,
+ ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, MapType, IsMapTypeImplicit,
+ DepLinMapLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
- Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, Locs);
break;
case OMPC_from:
- Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPFromClause(VarList, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, Locs);
break;
case OMPC_use_device_ptr:
- Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs);
break;
case OMPC_is_device_ptr:
- Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs);
+ break;
+ case OMPC_allocate:
+ Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
@@ -9759,66 +10798,6 @@ ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
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)) {
- Expr *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)) {
- Expr *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(
- getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
-}
-
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -10511,8 +11490,8 @@ public:
} // namespace
template <typename T, typename U>
-static T filterLookupForUDR(SmallVectorImpl<U> &Lookups,
- const llvm::function_ref<T(ValueDecl *)> Gen) {
+static T filterLookupForUDReductionAndMapper(
+ SmallVectorImpl<U> &Lookups, const llvm::function_ref<T(ValueDecl *)> Gen) {
for (U &Set : Lookups) {
for (auto *D : Set) {
if (T Res = Gen(cast<ValueDecl>(D)))
@@ -10539,7 +11518,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
}
static void
-argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId,
+argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &Id,
SourceLocation Loc, QualType Ty,
SmallVectorImpl<UnresolvedSet<8>> &Lookups) {
// Find all of the associated namespaces and classes based on the
@@ -10573,13 +11552,14 @@ argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
- DeclContext::lookup_result R = NS->lookup(ReductionId.getName());
+ DeclContext::lookup_result R = NS->lookup(Id.getName());
for (auto *D : R) {
auto *Underlying = D;
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
Underlying = USD->getTargetDecl();
- if (!isa<OMPDeclareReductionDecl>(Underlying))
+ if (!isa<OMPDeclareReductionDecl>(Underlying) &&
+ !isa<OMPDeclareMapperDecl>(Underlying))
continue;
if (!SemaRef.isVisible(D)) {
@@ -10624,7 +11604,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
for (NamedDecl *D : ULE->decls()) {
if (D == PrevD)
Lookups.push_back(UnresolvedSet<8>());
- else if (auto *DRD = cast<OMPDeclareReductionDecl>(D))
+ else if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(D))
Lookups.back().addDecl(DRD);
PrevD = D;
}
@@ -10632,7 +11612,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() ||
Ty->isInstantiationDependentType() ||
Ty->containsUnexpandedParameterPack() ||
- filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) {
+ filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) {
return !D->isInvalidDecl() &&
(D->getType()->isDependentType() ||
D->getType()->isInstantiationDependentType() ||
@@ -10680,33 +11660,38 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
}
}
// Perform ADL.
- argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups);
- if (auto *VD = filterLookupForUDR<ValueDecl *>(
+ if (SemaRef.getLangOpts().CPlusPlus)
+ argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups);
+ if (auto *VD = filterLookupForUDReductionAndMapper<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);
+ return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+ VK_LValue, Loc);
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ if (auto *VD = filterLookupForUDReductionAndMapper<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, VD->getType().getNonReferenceType(), VK_LValue, Loc);
+ }
}
}
}
@@ -11156,10 +12141,14 @@ static bool actOnOMPReductionKindClause(
if ((OASE && !ConstantLengthOASE) ||
(!OASE && !ASE &&
D->getType().getNonReferenceType()->isVariablyModifiedType())) {
- if (!Context.getTargetInfo().isVLASupported() &&
- S.shouldDiagnoseTargetSupportFromOpenMP()) {
- S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
- S.Diag(ELoc, diag::note_vla_unsupported);
+ if (!Context.getTargetInfo().isVLASupported()) {
+ if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) {
+ S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
+ S.Diag(ELoc, diag::note_vla_unsupported);
+ } else {
+ S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
+ S.targetDiag(ELoc, diag::note_vla_unsupported);
+ }
continue;
}
// For arrays/array sections only:
@@ -11300,7 +12289,8 @@ static bool actOnOMPReductionKindClause(
S.ActOnUninitializedDecl(RHSVD);
if (RHSVD->isInvalidDecl())
continue;
- if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
+ if (!RHSVD->hasInit() &&
+ (DeclareReductionRef.isUnset() || !S.LangOpts.CPlusPlus)) {
S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible)
<< Type << ReductionIdRange;
bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
@@ -12885,6 +13875,110 @@ static bool checkMapConflicts(
return FoundError;
}
+// Look up the user-defined mapper given the mapper name and mapped type, and
+// build a reference to it.
+static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
+ CXXScopeSpec &MapperIdScopeSpec,
+ const DeclarationNameInfo &MapperId,
+ QualType Type,
+ Expr *UnresolvedMapper) {
+ if (MapperIdScopeSpec.isInvalid())
+ return ExprError();
+ // Find all user-defined mappers with the given MapperId.
+ SmallVector<UnresolvedSet<8>, 4> Lookups;
+ LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
+ Lookup.suppressDiagnostics();
+ if (S) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) {
+ NamedDecl *D = Lookup.getRepresentativeDecl();
+ while (S && !S->isDeclScope(D))
+ S = S->getParent();
+ if (S)
+ S = S->getParent();
+ Lookups.emplace_back();
+ Lookups.back().append(Lookup.begin(), Lookup.end());
+ Lookup.clear();
+ }
+ } else if (auto *ULE = cast_or_null<UnresolvedLookupExpr>(UnresolvedMapper)) {
+ // Extract the user-defined mappers with the given MapperId.
+ Lookups.push_back(UnresolvedSet<8>());
+ for (NamedDecl *D : ULE->decls()) {
+ auto *DMD = cast<OMPDeclareMapperDecl>(D);
+ assert(DMD && "Expect valid OMPDeclareMapperDecl during instantiation.");
+ Lookups.back().addDecl(DMD);
+ }
+ }
+ // Defer the lookup for dependent types. The results will be passed through
+ // UnresolvedMapper on instantiation.
+ if (SemaRef.CurContext->isDependentContext() || Type->isDependentType() ||
+ Type->isInstantiationDependentType() ||
+ Type->containsUnexpandedParameterPack() ||
+ filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) {
+ return !D->isInvalidDecl() &&
+ (D->getType()->isDependentType() ||
+ D->getType()->isInstantiationDependentType() ||
+ D->getType()->containsUnexpandedParameterPack());
+ })) {
+ UnresolvedSet<8> URS;
+ for (const UnresolvedSet<8> &Set : Lookups) {
+ if (Set.empty())
+ continue;
+ URS.append(Set.begin(), Set.end());
+ }
+ return UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
+ /*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
+ }
+ // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
+ // The type must be of struct, union or class type in C and C++
+ if (!Type->isStructureOrClassType() && !Type->isUnionType())
+ return ExprEmpty();
+ SourceLocation Loc = MapperId.getLoc();
+ // Perform argument dependent lookup.
+ if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
+ argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups);
+ // Return the first user-defined mapper with the desired type.
+ if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
+ Lookups, [&SemaRef, Type](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.Context.hasSameType(D->getType(), Type))
+ return D;
+ return nullptr;
+ }))
+ return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc);
+ // Find the first user-defined mapper with a type derived from the desired
+ // type.
+ if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
+ Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.IsDerivedFrom(Loc, Type, D->getType()) &&
+ !Type.isMoreQualifiedThan(D->getType()))
+ return D;
+ return nullptr;
+ })) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SemaRef.IsDerivedFrom(Loc, Type, VD->getType(), Paths)) {
+ if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
+ VD->getType().getUnqualifiedType()))) {
+ if (SemaRef.CheckBaseClassAccess(
+ Loc, VD->getType(), Type, Paths.front(),
+ /*DiagID=*/0) != Sema::AR_inaccessible) {
+ return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc);
+ }
+ }
+ }
+ }
+ // Report error if a mapper is specified, but cannot be found.
+ if (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default") {
+ SemaRef.Diag(Loc, diag::err_omp_invalid_mapper)
+ << Type << MapperId.getName();
+ return ExprError();
+ }
+ return ExprEmpty();
+}
+
namespace {
// Utility struct that gathers all the related lists associated with a mappable
// expression.
@@ -12897,6 +13991,8 @@ struct MappableVarListInfo {
OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents;
// The base declaration of the variable.
SmallVector<ValueDecl *, 16> VarBaseDeclarations;
+ // The reference to the user-defined mapper associated with every expression.
+ SmallVector<Expr *, 16> UDMapperList;
MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) {
// We have a list of components and base declarations for each entry in the
@@ -12908,20 +14004,37 @@ struct MappableVarListInfo {
}
// 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) {
+// \a CKind. In the check process the valid expressions, mappable expression
+// components, variables, and user-defined mappers are extracted and used to
+// fill \a ProcessedVarList, \a VarComponents, \a VarBaseDeclarations, and \a
+// UDMapperList in MVLI. \a MapType, \a IsMapTypeImplicit, \a MapperIdScopeSpec,
+// and \a MapperId are expected to be valid if the clause kind is 'map'.
+static void checkMappableExpressionList(
+ Sema &SemaRef, DSAStackTy *DSAS, OpenMPClauseKind CKind,
+ MappableVarListInfo &MVLI, SourceLocation StartLoc,
+ CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId,
+ ArrayRef<Expr *> UnresolvedMappers,
+ 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!");
+ // If the identifier of user-defined mapper is not specified, it is "default".
+ // We do not change the actual name in this clause to distinguish whether a
+ // mapper is specified explicitly, i.e., it is not explicitly specified when
+ // MapperId.getName() is empty.
+ if (!MapperId.getName() || MapperId.getName().isEmpty()) {
+ auto &DeclNames = SemaRef.getASTContext().DeclarationNames;
+ MapperId.setName(DeclNames.getIdentifier(
+ &SemaRef.getASTContext().Idents.get("default")));
+ }
+
+ // Iterators to find the current unresolved mapper expression.
+ auto UMIt = UnresolvedMappers.begin(), UMEnd = UnresolvedMappers.end();
+ bool UpdateUMIt = false;
+ Expr *UnresolvedMapper = nullptr;
+
// 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.
@@ -12932,11 +14045,29 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
assert(RE && "Null expr in omp to/from/map clause");
SourceLocation ELoc = RE->getExprLoc();
+ // Find the current unresolved mapper expression.
+ if (UpdateUMIt && UMIt != UMEnd) {
+ UMIt++;
+ assert(
+ UMIt != UMEnd &&
+ "Expect the size of UnresolvedMappers to match with that of VarList");
+ }
+ UpdateUMIt = true;
+ if (UMIt != UMEnd)
+ UnresolvedMapper = *UMIt;
+
const Expr *VE = RE->IgnoreParenLValueCasts();
if (VE->isValueDependent() || VE->isTypeDependent() ||
VE->isInstantiationDependent() ||
VE->containsUnexpandedParameterPack()) {
+ // Try to find the associated user-defined mapper.
+ ExprResult ER = buildUserDefinedMapperRef(
+ SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
+ VE->getType().getCanonicalType(), UnresolvedMapper);
+ if (ER.isInvalid())
+ continue;
+ MVLI.UDMapperList.push_back(ER.get());
// We can only analyze this information once the missing information is
// resolved.
MVLI.ProcessedVarList.push_back(RE);
@@ -12968,6 +14099,13 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
if (const auto *TE = dyn_cast<CXXThisExpr>(BE)) {
// Add store "this" pointer to class in DSAStackTy for future checking
DSAS->addMappedClassesQualTypes(TE->getType());
+ // Try to find the associated user-defined mapper.
+ ExprResult ER = buildUserDefinedMapperRef(
+ SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
+ VE->getType().getCanonicalType(), UnresolvedMapper);
+ if (ER.isInvalid())
+ continue;
+ MVLI.UDMapperList.push_back(ER.get());
// Skip restriction checking for variable or field declarations
MVLI.ProcessedVarList.push_back(RE);
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
@@ -13086,6 +14224,14 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
}
}
+ // Try to find the associated user-defined mapper.
+ ExprResult ER = buildUserDefinedMapperRef(
+ SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
+ Type.getCanonicalType(), UnresolvedMapper);
+ if (ER.isInvalid())
+ continue;
+ MVLI.UDMapperList.push_back(ER.get());
+
// Save the current expression.
MVLI.ProcessedVarList.push_back(RE);
@@ -13105,19 +14251,16 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
}
}
-OMPClause *
-Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc,
- 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);
-
- OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown,
- OMPC_MAP_MODIFIER_unknown };
+OMPClause *Sema::ActOnOpenMPMapClause(
+ ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ ArrayRef<SourceLocation> MapTypeModifiersLoc,
+ CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
+ OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc,
+ SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
+ OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown,
+ OMPC_MAP_MODIFIER_unknown,
+ OMPC_MAP_MODIFIER_unknown};
SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers];
// Process map-type-modifiers, flag errors for duplicate modifiers.
@@ -13135,12 +14278,18 @@ Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
++Count;
}
+ MappableVarListInfo MVLI(VarList);
+ checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, Locs.StartLoc,
+ MapperIdScopeSpec, MapperId, UnresolvedMappers,
+ 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, Modifiers, ModifiersLoc,
- MapType, IsMapTypeImplicit, MapLoc);
+ return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations, MVLI.VarComponents,
+ MVLI.UDMapperList, Modifiers, ModifiersLoc,
+ MapperIdScopeSpec.getWithLocInContext(Context),
+ MapperId, MapType, IsMapTypeImplicit, MapLoc);
}
QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
@@ -13400,6 +14549,143 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
return DeclReductions;
}
+TypeResult Sema::ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D) {
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+ QualType T = TInfo->getType();
+ if (D.isInvalidType())
+ return true;
+
+ if (getLangOpts().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ return CreateParsedType(T, TInfo);
+}
+
+QualType Sema::ActOnOpenMPDeclareMapperType(SourceLocation TyLoc,
+ TypeResult ParsedType) {
+ assert(ParsedType.isUsable() && "Expect usable parsed mapper type");
+
+ QualType MapperType = GetTypeFromParser(ParsedType.get());
+ assert(!MapperType.isNull() && "Expect valid mapper type");
+
+ // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
+ // The type must be of struct, union or class type in C and C++
+ if (!MapperType->isStructureOrClassType() && !MapperType->isUnionType()) {
+ Diag(TyLoc, diag::err_omp_mapper_wrong_type);
+ return QualType();
+ }
+ return MapperType;
+}
+
+OMPDeclareMapperDecl *Sema::ActOnOpenMPDeclareMapperDirectiveStart(
+ Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType,
+ SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS,
+ Decl *PrevDeclInScope) {
+ LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPMapperName,
+ forRedeclarationInCurContext());
+ // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
+ // A mapper-identifier may not be redeclared 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;
+ OMPDeclareMapperDecl *PrevDMD = 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<OMPDeclareMapperDecl *, bool> UsedAsPrevious;
+ LookupResult::Filter Filter = Lookup.makeFilter();
+ while (Filter.hasNext()) {
+ auto *PrevDecl = cast<OMPDeclareMapperDecl>(Filter.next());
+ if (InCompoundScope) {
+ auto I = UsedAsPrevious.find(PrevDecl);
+ if (I == UsedAsPrevious.end())
+ UsedAsPrevious[PrevDecl] = false;
+ if (OMPDeclareMapperDecl *D = PrevDecl->getPrevDeclInScope())
+ UsedAsPrevious[D] = true;
+ }
+ PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
+ PrevDecl->getLocation();
+ }
+ Filter.done();
+ if (InCompoundScope) {
+ for (const auto &PrevData : UsedAsPrevious) {
+ if (!PrevData.second) {
+ PrevDMD = PrevData.first;
+ break;
+ }
+ }
+ }
+ } else if (PrevDeclInScope) {
+ auto *PrevDMDInScope = PrevDMD =
+ cast<OMPDeclareMapperDecl>(PrevDeclInScope);
+ do {
+ PreviousRedeclTypes[PrevDMDInScope->getType().getCanonicalType()] =
+ PrevDMDInScope->getLocation();
+ PrevDMDInScope = PrevDMDInScope->getPrevDeclInScope();
+ } while (PrevDMDInScope != nullptr);
+ }
+ const auto I = PreviousRedeclTypes.find(MapperType.getCanonicalType());
+ bool Invalid = false;
+ if (I != PreviousRedeclTypes.end()) {
+ Diag(StartLoc, diag::err_omp_declare_mapper_redefinition)
+ << MapperType << Name;
+ Diag(I->second, diag::note_previous_definition);
+ Invalid = true;
+ }
+ auto *DMD = OMPDeclareMapperDecl::Create(Context, DC, StartLoc, Name,
+ MapperType, VN, PrevDMD);
+ DC->addDecl(DMD);
+ DMD->setAccess(AS);
+ if (Invalid)
+ DMD->setInvalidDecl();
+
+ // Enter new function scope.
+ PushFunctionScope();
+ setFunctionHasBranchProtectedScope();
+
+ CurContext = DMD;
+
+ return DMD;
+}
+
+void Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD,
+ Scope *S,
+ QualType MapperType,
+ SourceLocation StartLoc,
+ DeclarationName VN) {
+ VarDecl *VD = buildVarDecl(*this, StartLoc, MapperType, VN.getAsString());
+ if (S)
+ PushOnScopeChains(VD, S);
+ else
+ DMD->addDecl(VD);
+ Expr *MapperVarRefExpr = buildDeclRefExpr(*this, VD, MapperType, StartLoc);
+ DMD->setMapperVarRef(MapperVarRefExpr);
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S,
+ ArrayRef<OMPClause *> ClauseList) {
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ if (D) {
+ if (S)
+ PushOnScopeChains(D, S, /*AddToContext=*/false);
+ D->CreateClauses(Context, ClauseList);
+ }
+
+ return DeclGroupPtrTy::make(DeclGroupRef(D));
+}
+
OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -13632,9 +14918,9 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
Lookup.suppressDiagnostics();
if (!Lookup.isSingleResult()) {
+ VarOrFuncDeclFilterCCC CCC(*this);
if (TypoCorrection Corrected =
- CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr,
- llvm::make_unique<VarOrFuncDeclFilterCCC>(*this),
+ CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC,
CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Id.getName());
@@ -13744,37 +15030,41 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
}
OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperId,
+ const OMPVarListLocTy &Locs,
+ ArrayRef<Expr *> UnresolvedMappers) {
MappableVarListInfo MVLI(VarList);
- checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc);
+ checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, Locs.StartLoc,
+ MapperIdScopeSpec, MapperId, UnresolvedMappers);
if (MVLI.ProcessedVarList.empty())
return nullptr;
- return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
- MVLI.VarComponents);
+ return OMPToClause::Create(
+ Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MVLI.UDMapperList,
+ MapperIdScopeSpec.getWithLocInContext(Context), MapperId);
}
OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperId,
+ const OMPVarListLocTy &Locs,
+ ArrayRef<Expr *> UnresolvedMappers) {
MappableVarListInfo MVLI(VarList);
- checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc);
+ checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, Locs.StartLoc,
+ MapperIdScopeSpec, MapperId, UnresolvedMappers);
if (MVLI.ProcessedVarList.empty())
return nullptr;
- return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
- MVLI.VarComponents);
+ return OMPFromClause::Create(
+ Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MVLI.UDMapperList,
+ MapperIdScopeSpec.getWithLocInContext(Context), MapperId);
}
OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ const OMPVarListLocTy &Locs) {
MappableVarListInfo MVLI(VarList);
SmallVector<Expr *, 8> PrivateCopies;
SmallVector<Expr *, 8> Inits;
@@ -13854,14 +15144,12 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
return nullptr;
return OMPUseDevicePtrClause::Create(
- Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList,
- PrivateCopies, Inits, MVLI.VarBaseDeclarations, MVLI.VarComponents);
+ Context, Locs, MVLI.ProcessedVarList, PrivateCopies, Inits,
+ MVLI.VarBaseDeclarations, MVLI.VarComponents);
}
OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ const OMPVarListLocTy &Locs) {
MappableVarListInfo MVLI(VarList);
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause.");
@@ -13937,7 +15225,68 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
if (MVLI.ProcessedVarList.empty())
return nullptr;
- return OMPIsDevicePtrClause::Create(
- Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList,
- MVLI.VarBaseDeclarations, MVLI.VarComponents);
+ return OMPIsDevicePtrClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
+OMPClause *Sema::ActOnOpenMPAllocateClause(
+ Expr *Allocator, ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
+ if (Allocator) {
+ // OpenMP [2.11.4 allocate Clause, Description]
+ // allocator is an expression of omp_allocator_handle_t type.
+ if (!findOMPAllocatorHandleT(*this, Allocator->getExprLoc(), DSAStack))
+ return nullptr;
+
+ ExprResult AllocatorRes = DefaultLvalueConversion(Allocator);
+ if (AllocatorRes.isInvalid())
+ return nullptr;
+ AllocatorRes = PerformImplicitConversion(AllocatorRes.get(),
+ DSAStack->getOMPAllocatorHandleT(),
+ Sema::AA_Initializing,
+ /*AllowExplicit=*/true);
+ if (AllocatorRes.isInvalid())
+ return nullptr;
+ Allocator = AllocatorRes.get();
+ } else {
+ // OpenMP 5.0, 2.11.4 allocate Clause, Restrictions.
+ // allocate clauses that appear on a target construct or on constructs in a
+ // target region must specify an allocator expression unless a requires
+ // directive with the dynamic_allocators clause is present in the same
+ // compilation unit.
+ if (LangOpts.OpenMPIsDevice &&
+ !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
+ targetDiag(StartLoc, diag::err_expected_allocator_expression);
+ }
+ // Analyze and build list of variables.
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP private 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;
+
+ auto *VD = dyn_cast<VarDecl>(D);
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && !CurContext->isDependentContext())
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ Vars.push_back((VD || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator,
+ ColonLoc, EndLoc, Vars);
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 52be0598fbc0..f632a4d3bd1a 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1,9 +1,8 @@
//===--- SemaOverload.cpp - C++ Overloading -------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -1057,6 +1056,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
// third bullet. If the type of the friend is dependent, skip this lookup
// until instantiation.
if (New->getFriendObjectKind() && New->getQualifier() &&
+ !New->getDescribedFunctionTemplate() &&
!New->getDependentSpecializationInfo() &&
!New->getType()->isDependentType()) {
LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
@@ -1172,16 +1172,14 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// function yet (because we haven't yet resolved whether this is a static
// or non-static member function). Add it now, on the assumption that this
// is a redeclaration of OldMethod.
- // FIXME: OpenCL: Need to consider address spaces
- unsigned OldQuals = OldMethod->getTypeQualifiers().getCVRUQualifiers();
- unsigned NewQuals = NewMethod->getTypeQualifiers().getCVRUQualifiers();
+ auto OldQuals = OldMethod->getMethodQualifiers();
+ auto NewQuals = NewMethod->getMethodQualifiers();
if (!getLangOpts().CPlusPlus14 && NewMethod->isConstexpr() &&
!isa<CXXConstructorDecl>(NewMethod))
- NewQuals |= Qualifiers::Const;
-
+ NewQuals.addConst();
// We do not allow overloading based off of '__restrict'.
- OldQuals &= ~Qualifiers::Restrict;
- NewQuals &= ~Qualifiers::Restrict;
+ OldQuals.removeRestrict();
+ NewQuals.removeRestrict();
if (OldQuals != NewQuals)
return true;
}
@@ -1232,24 +1230,6 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return false;
}
-/// Checks availability of the function depending on the current
-/// function context. Inside an unavailable function, unavailability is ignored.
-///
-/// \returns true if \arg FD is unavailable and current context is inside
-/// an available function, false otherwise.
-bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
- 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;
-}
-
/// Tries a user-defined conversion from From to ToType.
///
/// Produces an implicit conversion sequence for when a standard conversion
@@ -1871,6 +1851,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
(From->EvaluateKnownConstInt(S.getASTContext()) == 0)) {
SCS.Second = ICK_Zero_Queue_Conversion;
FromType = ToType;
+ } else if (ToType->isSamplerT() &&
+ From->isIntegerConstantExpr(S.getASTContext())) {
+ SCS.Second = ICK_Compatible_Conversion;
+ FromType = ToType;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@@ -1970,7 +1954,7 @@ IsTransparentUnionStandardConversion(Sema &S, Expr* From,
// It's compatible if the expression matches any of the fields.
for (const auto *it : UD->fields()) {
if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
- CStyle, /*ObjCWritebackConversion=*/false)) {
+ CStyle, /*AllowObjCWritebackConversion=*/false)) {
ToType = it->getType();
return true;
}
@@ -2547,7 +2531,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// function types are obviously different.
if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic() ||
- FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals())
+ FromFunctionType->getMethodQuals() != ToFunctionType->getMethodQuals())
return false;
bool HasObjCConversion = false;
@@ -2854,9 +2838,9 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
return;
}
- if (FromFunction->getTypeQuals() != ToFunction->getTypeQuals()) {
- PDiag << ft_qualifer_mismatch << ToFunction->getTypeQuals()
- << FromFunction->getTypeQuals();
+ if (FromFunction->getMethodQuals() != ToFunction->getMethodQuals()) {
+ PDiag << ft_qualifer_mismatch << ToFunction->getMethodQuals()
+ << FromFunction->getMethodQuals();
return;
}
@@ -3262,10 +3246,13 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, From,
- CandidateSet, SuppressUserConversions);
+ CandidateSet, SuppressUserConversions,
+ /*PartialOverloading*/ false,
+ AllowExplicit);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From,
- CandidateSet, SuppressUserConversions);
+ CandidateSet, SuppressUserConversions,
+ /*PartialOverloading*/ false, AllowExplicit);
}
}
@@ -3392,13 +3379,15 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
- CandidateSet, SuppressUserConversions);
+ CandidateSet, SuppressUserConversions,
+ /*PartialOverloading*/ false, AllowExplicit);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
llvm::makeArrayRef(Args, NumArgs),
- CandidateSet, SuppressUserConversions);
+ CandidateSet, SuppressUserConversions,
+ /*PartialOverloading*/ false, AllowExplicit);
}
}
}
@@ -3430,14 +3419,13 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, FoundDecl,
- ActingContext, From, ToType,
- CandidateSet,
- AllowObjCConversionOnExplicit);
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, FoundDecl, ActingContext, From, ToType,
+ CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
else
- S.AddConversionCandidate(Conv, FoundDecl, ActingContext,
- From, ToType, CandidateSet,
- AllowObjCConversionOnExplicit);
+ S.AddConversionCandidate(
+ Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
+ AllowObjCConversionOnExplicit, AllowExplicit);
}
}
}
@@ -3525,18 +3513,25 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
CandidateSet, false, false);
+
+ if (!(OvResult == OR_Ambiguous ||
+ (OvResult == OR_No_Viable_Function && !CandidateSet.empty())))
+ return false;
+
+ auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, From);
if (OvResult == OR_Ambiguous)
Diag(From->getBeginLoc(), diag::err_typecheck_ambiguous_condition)
<< From->getType() << ToType << From->getSourceRange();
- else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) {
+ else { // OR_No_Viable_Function && !CandidateSet.empty()
if (!RequireCompleteType(From->getBeginLoc(), ToType,
diag::err_typecheck_nonviable_condition_incomplete,
From->getType(), From->getSourceRange()))
Diag(From->getBeginLoc(), diag::err_typecheck_nonviable_condition)
<< false << From->getType() << From->getSourceRange() << ToType;
- } else
- return false;
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, From);
+ }
+
+ CandidateSet.NoteCandidates(
+ *this, From, Cands);
return true;
}
@@ -4019,9 +4014,12 @@ CompareQualificationConversions(Sema &S,
// to unwrap. This essentially mimics what
// IsQualificationConversion does, but here we're checking for a
// strict subset of qualifiers.
- if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+ if (T1.getQualifiers().withoutObjCLifetime() ==
+ T2.getQualifiers().withoutObjCLifetime())
// The qualifiers are the same, so this doesn't tell us anything
// about how the sequences rank.
+ // ObjC ownership quals are omitted above as they interfere with
+ // the ARC overload rule.
;
else if (T2.isMoreQualifiedThan(T1)) {
// T1 has fewer qualifiers, so it could be the better sequence.
@@ -4455,13 +4453,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
}
if (ConvTemplate)
- S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
- Init, DeclType, CandidateSet,
- /*AllowObjCConversionOnExplicit=*/false);
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false, AllowExplicit);
else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
- DeclType, CandidateSet,
- /*AllowObjCConversionOnExplicit=*/false);
+ S.AddConversionCandidate(
+ Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false, AllowExplicit);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -5095,12 +5093,10 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType,
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
// [class.dtor]p2: A destructor can be invoked for a const, volatile or
// const volatile object.
- Qualifiers Quals;
+ Qualifiers Quals = Method->getMethodQualifiers();
if (isa<CXXDestructorDecl>(Method)) {
Quals.addConst();
Quals.addVolatile();
- } else {
- Quals = Method->getTypeQualifiers();
}
QualType ImplicitParamType = S.Context.getQualifiedType(ClassType, Quals);
@@ -5148,6 +5144,16 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType,
return ICS;
}
+ if (FromTypeCanon.getQualifiers().hasAddressSpace()) {
+ Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers();
+ Qualifiers QualsFromType = FromTypeCanon.getQualifiers();
+ if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) {
+ ICS.setBad(BadConversionSequence::bad_qualifiers,
+ FromType, ImplicitParamType);
+ return ICS;
+ }
+ }
+
// Check that we have either the same type or a derived type. It
// affects the conversion rank.
QualType ClassTypeCanon = S.Context.getCanonicalType(ClassType);
@@ -5286,12 +5292,12 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
}
if (!Context.hasSameType(From->getType(), DestType)) {
- if (From->getType().getAddressSpace() != DestType.getAddressSpace())
- From = ImpCastExprToType(From, DestType, CK_AddressSpaceConversion,
- From->getValueKind()).get();
+ CastKind CK;
+ if (FromRecordType.getAddressSpace() != DestType.getAddressSpace())
+ CK = CK_AddressSpaceConversion;
else
- From = ImpCastExprToType(From, DestType, CK_NoOp,
- From->getValueKind()).get();
+ CK = CK_NoOp;
+ From = ImpCastExprToType(From, DestType, CK, From->getValueKind()).get();
}
return From;
}
@@ -5414,12 +5420,12 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
// condition shall be a contextually converted constant expression of type
// bool.
ImplicitConversionSequence ICS =
- CCE == Sema::CCEK_ConstexprIf
+ CCE == Sema::CCEK_ConstexprIf || CCE == Sema::CCEK_ExplicitBool
? TryContextuallyConvertToBool(S, From)
: TryCopyInitialization(S, From, T,
/*SuppressUserConversions=*/false,
/*InOverloadResolution=*/false,
- /*AllowObjcWritebackConversion=*/false,
+ /*AllowObjCWritebackConversion=*/false,
/*AllowExplicit=*/false);
StandardConversionSequence *SCS = nullptr;
switch (ICS.getKind()) {
@@ -5510,7 +5516,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
if (Notes.empty()) {
// It's a constant expression.
- return ConstantExpr::Create(S.Context, Result.get());
+ return ConstantExpr::Create(S.Context, Result.get(), Value);
}
}
@@ -5730,12 +5736,13 @@ collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType,
if (ConvTemplate)
SemaRef.AddTemplateConversionCandidate(
- ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
- /*AllowObjCConversionOnExplicit=*/false);
+ ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false, /*AllowExplicit*/ true);
else
SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
ToType, CandidateSet,
- /*AllowObjCConversionOnExplicit=*/false);
+ /*AllowObjCConversionOnExplicit=*/false,
+ /*AllowExplicit*/ true);
}
}
@@ -5987,13 +5994,11 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
/// \param PartialOverloading true if we are performing "partial" overloading
/// based on an incomplete set of function arguments. This feature is used by
/// code completion.
-void Sema::AddOverloadCandidate(FunctionDecl *Function,
- DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
- OverloadCandidateSet &CandidateSet,
- bool SuppressUserConversions,
- bool PartialOverloading, bool AllowExplicit,
- ADLCallKind IsADLCandidate,
- ConversionSequenceList EarlyConversions) {
+void Sema::AddOverloadCandidate(
+ FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+ bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
+ ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6098,6 +6103,15 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function,
return;
}
}
+
+ // Check that the constructor is capable of constructing an object in the
+ // destination address space.
+ if (!Qualifiers::isAddressSpaceSupersetOf(
+ Constructor->getMethodQualifiers().getAddressSpace(),
+ CandidateSet.getDestAS())) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_object_addrspace_mismatch;
+ }
}
unsigned NumParams = Proto->getNumParams();
@@ -6150,13 +6164,11 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function,
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getParamType(ArgIdx);
- Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
- SuppressUserConversions,
- /*InOverloadResolution=*/true,
- /*AllowObjCWritebackConversion=*/
- getLangOpts().ObjCAutoRefCount,
- AllowExplicit);
+ Candidate.Conversions[ArgIdx] = TryCopyInitialization(
+ *this, Args[ArgIdx], ParamType, SuppressUserConversions,
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -6170,6 +6182,15 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function,
}
}
+ if (!AllowExplicit) {
+ ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
+ if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit_resolved;
+ return;
+ }
+ }
+
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -6366,7 +6387,8 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
APValue Result;
// 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(
+ if (EIA->getCond()->isValueDependent() ||
+ !EIA->getCond()->EvaluateWithSubstitution(
Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)))
return EIA;
@@ -6759,7 +6781,7 @@ void Sema::AddTemplateOverloadCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
- bool PartialOverloading, ADLCallKind IsADLCandidate) {
+ bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) {
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
@@ -6808,9 +6830,10 @@ void Sema::AddTemplateOverloadCandidate(
// Add the function template specialization produced by template argument
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
- AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
- SuppressUserConversions, PartialOverloading,
- /*AllowExplicit*/ false, IsADLCandidate, Conversions);
+ AddOverloadCandidate(
+ Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
+ PartialOverloading, AllowExplicit,
+ /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions);
}
/// Check that implicit conversion sequences can be formed for each argument
@@ -6915,14 +6938,11 @@ static bool isAllowableExplicitConversion(Sema &S,
/// and ToType is the type that we're eventually trying to convert to
/// (which may or may not be the same type as the type that the
/// conversion function produces).
-void
-Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
- DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingContext,
- Expr *From, QualType ToType,
- OverloadCandidateSet& CandidateSet,
- bool AllowObjCConversionOnExplicit,
- bool AllowResultConversion) {
+void Sema::AddConversionCandidate(
+ CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
+ CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
+ bool AllowExplicit, bool AllowResultConversion) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -7081,6 +7101,13 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
"Can only end up with a standard conversion sequence or failure");
}
+ if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() !=
+ ExplicitSpecKind::ResolvedFalse) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit_resolved;
+ return;
+ }
+
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -7100,14 +7127,11 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/// to deduce the template arguments of the conversion function
/// template from the type that we are converting to (C++
/// [temp.deduct.conv]).
-void
-Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
- DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingDC,
- Expr *From, QualType ToType,
- OverloadCandidateSet &CandidateSet,
- bool AllowObjCConversionOnExplicit,
- bool AllowResultConversion) {
+void Sema::AddTemplateConversionCandidate(
+ FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+ CXXRecordDecl *ActingDC, Expr *From, QualType ToType,
+ OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
+ bool AllowExplicit, bool AllowResultConversion) {
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
"Only conversion function templates permitted here");
@@ -7137,7 +7161,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
CandidateSet, AllowObjCConversionOnExplicit,
- AllowResultConversion);
+ AllowExplicit, AllowResultConversion);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -7297,7 +7321,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
++Oper)
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args.slice(1),
- CandidateSet, /*SuppressUserConversions=*/false);
+ CandidateSet, /*SuppressUserConversion=*/false);
}
}
@@ -7649,6 +7673,12 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
}
}
}
+/// Helper function for adjusting address spaces for the pointer or reference
+/// operands of builtin operators depending on the argument.
+static QualType AdjustAddressSpaceForBuiltinOperandType(Sema &S, QualType T,
+ Expr *Arg) {
+ return S.Context.getAddrSpaceQualType(T, Arg->getType().getAddressSpace());
+}
/// Helper function for AddBuiltinOperatorCandidates() that adds
/// the volatile- and non-volatile-qualified assignment operators for the
@@ -7660,15 +7690,17 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
QualType ParamTypes[2];
// T& operator=(T&, T)
- ParamTypes[0] = S.Context.getLValueReferenceType(T);
+ ParamTypes[0] = S.Context.getLValueReferenceType(
+ AdjustAddressSpaceForBuiltinOperandType(S, T, Args[0]));
ParamTypes[1] = T;
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/true);
if (!S.Context.getCanonicalType(T).isVolatileQualified()) {
// volatile T& operator=(volatile T&, T)
- ParamTypes[0]
- = S.Context.getLValueReferenceType(S.Context.getVolatileType(T));
+ ParamTypes[0] = S.Context.getLValueReferenceType(
+ AdjustAddressSpaceForBuiltinOperandType(S, S.Context.getVolatileType(T),
+ Args[0]));
ParamTypes[1] = T;
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/true);
@@ -7947,7 +7979,7 @@ public:
continue;
if (const FunctionProtoType *Proto =PointeeTy->getAs<FunctionProtoType>())
- if (Proto->getTypeQuals() || Proto->getRefQualifier())
+ if (Proto->getMethodQuals() || Proto->getRefQualifier())
continue;
S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
@@ -8390,7 +8422,7 @@ public:
isEqualOp ? *Ptr : S.Context.getPointerDiffType(),
};
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/ isEqualOp);
+ /*IsAssignmentOperator=*/ isEqualOp);
bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile();
@@ -8399,7 +8431,7 @@ public:
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
}
if (!(*Ptr).isRestrictQualified() &&
@@ -8408,7 +8440,7 @@ public:
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
if (NeedVolatile) {
// volatile restrict version
@@ -8418,7 +8450,7 @@ public:
(Qualifiers::Volatile |
Qualifiers::Restrict)));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
}
}
}
@@ -8439,7 +8471,7 @@ public:
// non-volatile version
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/true);
+ /*IsAssignmentOperator=*/true);
bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile();
@@ -8448,7 +8480,7 @@ public:
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/true);
+ /*IsAssignmentOperator=*/true);
}
if (!(*Ptr).isRestrictQualified() &&
@@ -8457,7 +8489,7 @@ public:
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/true);
+ /*IsAssignmentOperator=*/true);
if (NeedVolatile) {
// volatile restrict version
@@ -8467,7 +8499,7 @@ public:
(Qualifiers::Volatile |
Qualifiers::Restrict)));
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/true);
+ /*IsAssignmentOperator=*/true);
}
}
}
@@ -8495,20 +8527,19 @@ public:
Right < LastPromotedArithmeticType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
-
+ auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType(
+ S, ArithmeticTypes[Left], Args[0]);
// Add this built-in operator as a candidate (VQ is empty).
- ParamTypes[0] =
- S.Context.getLValueReferenceType(ArithmeticTypes[Left]);
+ ParamTypes[0] = S.Context.getLValueReferenceType(LeftBaseTy);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
- ParamTypes[0] =
- S.Context.getVolatileType(ArithmeticTypes[Left]);
+ ParamTypes[0] = S.Context.getVolatileType(LeftBaseTy);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
}
}
}
@@ -8527,14 +8558,14 @@ public:
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
ParamTypes[0] = S.Context.getVolatileType(*Vec1);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssigmentOperator=*/isEqualOp);
+ /*IsAssignmentOperator=*/isEqualOp);
}
}
}
@@ -8561,14 +8592,14 @@ public:
Right < LastPromotedIntegralType; ++Right) {
QualType ParamTypes[2];
ParamTypes[1] = ArithmeticTypes[Right];
-
+ auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType(
+ S, ArithmeticTypes[Left], Args[0]);
// Add this built-in operator as a candidate (VQ is empty).
- ParamTypes[0] =
- S.Context.getLValueReferenceType(ArithmeticTypes[Left]);
+ ParamTypes[0] = S.Context.getLValueReferenceType(LeftBaseTy);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
if (VisibleTypeConversionsQuals.hasVolatile()) {
// Add this built-in operator as a candidate (VQ is 'volatile').
- ParamTypes[0] = ArithmeticTypes[Left];
+ ParamTypes[0] = LeftBaseTy;
ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
@@ -8983,13 +9014,16 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
continue;
AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
- /*SupressUserConversions=*/false, PartialOverloading,
- /*AllowExplicit=*/false, ADLCallKind::UsesADL);
+ /*SuppressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit*/ true,
+ /*AllowExplicitConversions*/ false,
+ ADLCallKind::UsesADL);
} else {
- AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl,
- ExplicitTemplateArgs, Args, CandidateSet,
- /*SupressUserConversions=*/false,
- PartialOverloading, ADLCallKind::UsesADL);
+ AddTemplateOverloadCandidate(
+ cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
+ CandidateSet,
+ /*SuppressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit*/true, ADLCallKind::UsesADL);
}
}
}
@@ -9436,9 +9470,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
}
// Best is the best viable function.
- if (Best->Function &&
- (Best->Function->isDeleted() ||
- S.isFunctionConsideredUnavailable(Best->Function)))
+ if (Best->Function && Best->Function->isDeleted())
return OR_Deleted;
if (!EquivalentCands.empty())
@@ -9542,7 +9574,8 @@ static bool isFunctionAlwaysEnabled(const ASTContext &Ctx,
const FunctionDecl *FD) {
for (auto *EnableIf : FD->specific_attrs<EnableIfAttr>()) {
bool AlwaysTrue;
- if (!EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx))
+ if (EnableIf->getCond()->isValueDependent() ||
+ !EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx))
return false;
if (!AlwaysTrue)
return false;
@@ -10322,6 +10355,33 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
}
+static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
+ ExplicitSpecifier ES;
+ const char *DeclName;
+ switch (Cand->Function->getDeclKind()) {
+ case Decl::Kind::CXXConstructor:
+ ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
+ DeclName = "constructor";
+ break;
+ case Decl::Kind::CXXConversion:
+ ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
+ DeclName = "conversion operator";
+ break;
+ case Decl::Kind::CXXDeductionGuide:
+ ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
+ DeclName = "deductiong guide";
+ break;
+ default:
+ llvm_unreachable("invalid Decl");
+ }
+ assert(ES.getExpr() && "null expression should be handled before");
+ S.Diag(Cand->Function->getLocation(),
+ diag::note_ovl_candidate_explicit_forbidden)
+ << DeclName;
+ S.Diag(ES.getExpr()->getBeginLoc(),
+ diag::note_explicit_bool_resolved_to_true);
+}
+
static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
FunctionDecl *Callee = Cand->Function;
@@ -10343,14 +10403,17 @@ static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
/// It would be great to be able to express per-candidate problems
/// more richly for those diagnostic clients that cared, but we'd
/// still have to be just as careful with the default diagnostics.
+/// \param CtorDestAS Addr space of object being constructed (for ctor
+/// candidates only).
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
unsigned NumArgs,
- bool TakingCandidateAddress) {
+ bool TakingCandidateAddress,
+ LangAS CtorDestAS = LangAS::Default) {
FunctionDecl *Fn = Cand->Function;
// Note deleted candidates, but only if they're viable.
if (Cand->Viable) {
- if (Fn->isDeleted() || S.isFunctionConsideredUnavailable(Fn)) {
+ if (Fn->isDeleted()) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
@@ -10383,6 +10446,16 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
+ case ovl_fail_object_addrspace_mismatch: {
+ Qualifiers QualsForPrinting;
+ QualsForPrinting.setAddressSpace(CtorDestAS);
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_illegal_constructor_adrspace_mismatch)
+ << QualsForPrinting;
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
+ return;
+ }
+
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
@@ -10406,6 +10479,9 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
+ case ovl_fail_explicit_resolved:
+ return DiagnoseFailedExplicitSpec(S, Cand);
+
case ovl_fail_ext_disabled:
return DiagnoseOpenCLExtensionDisabled(S, Cand);
@@ -10747,11 +10823,9 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
}
-/// When overload resolution fails, prints diagnostic messages containing the
-/// candidates in the candidate set.
-void OverloadCandidateSet::NoteCandidates(
+SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates(
Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args,
- StringRef Opc, SourceLocation OpLoc,
+ SourceLocation OpLoc,
llvm::function_ref<bool(OverloadCandidate &)> Filter) {
// Sort the candidates by viability and position. Sorting directly would
// be prohibitive, so we make a set of pointers and sort those.
@@ -10771,15 +10845,35 @@ void OverloadCandidateSet::NoteCandidates(
}
}
- std::stable_sort(Cands.begin(), Cands.end(),
- CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
+ llvm::stable_sort(
+ Cands, CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
+ return Cands;
+}
+
+/// When overload resolution fails, prints diagnostic messages containing the
+/// candidates in the candidate set.
+void OverloadCandidateSet::NoteCandidates(PartialDiagnosticAt PD,
+ Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args,
+ StringRef Opc, SourceLocation OpLoc,
+ llvm::function_ref<bool(OverloadCandidate &)> Filter) {
+
+ auto Cands = CompleteCandidates(S, OCD, Args, OpLoc, Filter);
+
+ S.Diag(PD.first, PD.second);
+
+ NoteCandidates(S, Args, Cands, Opc, OpLoc);
+}
+
+void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
+ ArrayRef<OverloadCandidate *> Cands,
+ StringRef Opc, SourceLocation OpLoc) {
bool ReportedAmbiguousConversions = false;
- SmallVectorImpl<OverloadCandidate*>::iterator I, E;
const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
unsigned CandsShown = 0;
- for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
+ auto I = Cands.begin(), E = Cands.end();
+ for (; I != E; ++I) {
OverloadCandidate *Cand = *I;
// Set an arbitrary limit on the number of candidate functions we'll spam
@@ -10792,7 +10886,7 @@ void OverloadCandidateSet::NoteCandidates(
if (Cand->Function)
NoteFunctionCandidate(S, Cand, Args.size(),
- /*TakingCandidateAddress=*/false);
+ /*TakingCandidateAddress=*/false, DestAS);
else if (Cand->IsSurrogate)
NoteSurrogateCandidate(S, Cand);
else {
@@ -11671,7 +11765,7 @@ static void AddOverloadedCallCandidate(Sema &S,
return;
S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet,
- /*SuppressUsedConversions=*/false,
+ /*SuppressUserConversions=*/false,
PartialOverloading);
return;
}
@@ -11680,7 +11774,7 @@ static void AddOverloadedCallCandidate(Sema &S,
= dyn_cast<FunctionTemplateDecl>(Callee)) {
S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl,
ExplicitTemplateArgs, Args, CandidateSet,
- /*SuppressUsedConversions=*/false,
+ /*SuppressUserConversions=*/false,
PartialOverloading);
return;
}
@@ -11895,15 +11989,6 @@ public:
}
-static std::unique_ptr<CorrectionCandidateCallback>
-MakeValidator(Sema &SemaRef, MemberExpr *ME, size_t NumArgs,
- bool HasTemplateArgs, bool AllowTypoCorrection) {
- if (!AllowTypoCorrection)
- return llvm::make_unique<NoTypoCorrectionCCC>();
- return llvm::make_unique<FunctionCallFilterCCC>(SemaRef, NumArgs,
- HasTemplateArgs, ME);
-}
-
/// Attempts to recover from a call where no functions were found.
///
/// Returns true if new candidates were found.
@@ -11938,16 +12023,22 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
bool DoDiagnoseEmptyLookup = EmptyLookup;
- if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
- OverloadCandidateSet::CSK_Normal,
- ExplicitTemplateArgs, Args,
- &DoDiagnoseEmptyLookup) &&
- (!DoDiagnoseEmptyLookup || SemaRef.DiagnoseEmptyLookup(
- S, SS, R,
- MakeValidator(SemaRef, dyn_cast<MemberExpr>(Fn), Args.size(),
- ExplicitTemplateArgs != nullptr, AllowTypoCorrection),
- ExplicitTemplateArgs, Args)))
- return ExprError();
+ if (!DiagnoseTwoPhaseLookup(
+ SemaRef, Fn->getExprLoc(), SS, R, OverloadCandidateSet::CSK_Normal,
+ ExplicitTemplateArgs, Args, &DoDiagnoseEmptyLookup)) {
+ NoTypoCorrectionCCC NoTypoValidator{};
+ FunctionCallFilterCCC FunctionCallValidator(SemaRef, Args.size(),
+ ExplicitTemplateArgs != nullptr,
+ dyn_cast<MemberExpr>(Fn));
+ CorrectionCandidateCallback &Validator =
+ AllowTypoCorrection
+ ? static_cast<CorrectionCandidateCallback &>(FunctionCallValidator)
+ : static_cast<CorrectionCandidateCallback &>(NoTypoValidator);
+ if (!DoDiagnoseEmptyLookup ||
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, Validator, ExplicitTemplateArgs,
+ Args))
+ return ExprError();
+ }
assert(!R.empty() && "lookup results empty despite recovery");
@@ -11975,7 +12066,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
// This shouldn't cause an infinite loop because we're giving it
// an expression with viable lookup results, which should never
// end up here.
- return SemaRef.ActOnCallExpr(/*Scope*/ nullptr, NewFn.get(), LParenLoc,
+ return SemaRef.BuildCallExpr(/*Scope*/ nullptr, NewFn.get(), LParenLoc,
MultiExprArg(Args.data(), Args.size()),
RParenLoc);
}
@@ -11997,7 +12088,8 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
// We don't perform ADL for implicit declarations of builtins.
// Verify that this was correctly set up.
FunctionDecl *F;
- if (ULE->decls_begin() + 1 == ULE->decls_end() &&
+ if (ULE->decls_begin() != ULE->decls_end() &&
+ ULE->decls_begin() + 1 == ULE->decls_end() &&
(F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) &&
F->getBuiltinID() && F->isImplicit())
llvm_unreachable("performing ADL for builtin");
@@ -12101,24 +12193,29 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
}
}
- SemaRef.Diag(Fn->getBeginLoc(), diag::err_ovl_no_viable_function_in_call)
- << ULE->getName() << Fn->getSourceRange();
- CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args);
+ CandidateSet->NoteCandidates(
+ PartialDiagnosticAt(
+ Fn->getBeginLoc(),
+ SemaRef.PDiag(diag::err_ovl_no_viable_function_in_call)
+ << ULE->getName() << Fn->getSourceRange()),
+ SemaRef, OCD_AllCandidates, Args);
break;
}
case OR_Ambiguous:
- SemaRef.Diag(Fn->getBeginLoc(), diag::err_ovl_ambiguous_call)
- << ULE->getName() << Fn->getSourceRange();
- CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates, Args);
+ CandidateSet->NoteCandidates(
+ PartialDiagnosticAt(Fn->getBeginLoc(),
+ SemaRef.PDiag(diag::err_ovl_ambiguous_call)
+ << ULE->getName() << Fn->getSourceRange()),
+ SemaRef, OCD_ViableCandidates, Args);
break;
case OR_Deleted: {
- SemaRef.Diag(Fn->getBeginLoc(), diag::err_ovl_deleted_call)
- << (*Best)->Function->isDeleted() << ULE->getName()
- << SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function)
- << Fn->getSourceRange();
- CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args);
+ CandidateSet->NoteCandidates(
+ PartialDiagnosticAt(Fn->getBeginLoc(),
+ SemaRef.PDiag(diag::err_ovl_deleted_call)
+ << ULE->getName() << Fn->getSourceRange()),
+ SemaRef, OCD_AllCandidates, Args);
// We emitted an error for the unavailable/deleted function call but keep
// the call in the AST.
@@ -12176,10 +12273,9 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
OverloadingResult OverloadResult =
CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best);
- return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args,
- RParenLoc, ExecConfig, &CandidateSet,
- &Best, OverloadResult,
- AllowTypoCorrection);
+ return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, RParenLoc,
+ ExecConfig, &CandidateSet, &Best,
+ OverloadResult, AllowTypoCorrection);
}
static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
@@ -12352,22 +12448,22 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
break;
case OR_Ambiguous:
- Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary)
- << UnaryOperator::getOpcodeStr(Opc)
- << Input->getType()
- << Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, ArgsArray,
- UnaryOperator::getOpcodeStr(Opc), OpLoc);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(OpLoc,
+ PDiag(diag::err_ovl_ambiguous_oper_unary)
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Input->getType() << Input->getSourceRange()),
+ *this, OCD_ViableCandidates, ArgsArray,
+ UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
case OR_Deleted:
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
- << UnaryOperator::getOpcodeStr(Opc)
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Input->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, ArgsArray,
- UnaryOperator::getOpcodeStr(Opc), OpLoc);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Input->getSourceRange()),
+ *this, OCD_AllCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc),
+ OpLoc);
return ExprError();
}
@@ -12601,6 +12697,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// operator do not fall through to handling in built-in, but report that
// no overloaded assignment operator found
ExprResult Result = ExprError();
+ StringRef OpcStr = BinaryOperator::getOpcodeStr(Opc);
+ auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates,
+ Args, OpLoc);
if (Args[0]->getType()->isRecordType() &&
Opc >= BO_Assign && Opc <= BO_OrAssign) {
Diag(OpLoc, diag::err_ovl_no_viable_oper)
@@ -12625,19 +12724,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
}
assert(Result.isInvalid() &&
"C++ binary operator overloading is missing candidates!");
- if (Result.isInvalid())
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
- BinaryOperator::getOpcodeStr(Opc), OpLoc);
+ CandidateSet.NoteCandidates(*this, Args, Cands, OpcStr, OpLoc);
return Result;
}
case OR_Ambiguous:
- Diag(OpLoc, diag::err_ovl_ambiguous_oper_binary)
- << BinaryOperator::getOpcodeStr(Opc)
- << Args[0]->getType() << Args[1]->getType()
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args,
- BinaryOperator::getOpcodeStr(Opc), OpLoc);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getType()
+ << Args[1]->getType()
+ << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange()),
+ *this, OCD_ViableCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
+ OpLoc);
return ExprError();
case OR_Deleted:
@@ -12651,15 +12751,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// explain why it's deleted.
NoteDeletedFunction(Method);
return ExprError();
- } else {
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
- << BinaryOperator::getOpcodeStr(Opc)
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
}
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
- BinaryOperator::getOpcodeStr(Opc), OpLoc);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange()),
+ *this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
+ OpLoc);
return ExprError();
}
@@ -12801,35 +12900,34 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
case OR_No_Viable_Function: {
- if (CandidateSet.empty())
- Diag(LLoc, diag::err_ovl_no_oper)
- << Args[0]->getType() << /*subscript*/ 0
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- else
- Diag(LLoc, diag::err_ovl_no_viable_subscript)
- << Args[0]->getType()
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
- "[]", LLoc);
+ PartialDiagnostic PD = CandidateSet.empty()
+ ? (PDiag(diag::err_ovl_no_oper)
+ << Args[0]->getType() << /*subscript*/ 0
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange())
+ : (PDiag(diag::err_ovl_no_viable_subscript)
+ << Args[0]->getType() << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange());
+ CandidateSet.NoteCandidates(PartialDiagnosticAt(LLoc, PD), *this,
+ OCD_AllCandidates, Args, "[]", LLoc);
return ExprError();
}
case OR_Ambiguous:
- Diag(LLoc, diag::err_ovl_ambiguous_oper_binary)
- << "[]"
- << Args[0]->getType() << Args[1]->getType()
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args,
- "[]", LLoc);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
+ << "[]" << Args[0]->getType()
+ << Args[1]->getType()
+ << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange()),
+ *this, OCD_ViableCandidates, Args, "[]", LLoc);
return ExprError();
case OR_Deleted:
- Diag(LLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted() << "[]"
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args,
- "[]", LLoc);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_deleted_oper)
+ << "[]" << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange()),
+ *this, OCD_AllCandidates, Args, "[]", LLoc);
return ExprError();
}
@@ -12870,7 +12968,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Check that the object type isn't more qualified than the
// member function we're calling.
- Qualifiers funcQuals = proto->getTypeQuals();
+ Qualifiers funcQuals = proto->getMethodQuals();
QualType objectType = op->getLHS()->getType();
if (op->getOpcode() == BO_PtrMemI)
@@ -12954,8 +13052,9 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Microsoft supports direct constructor calls.
if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
- AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(),
- Args, CandidateSet);
+ AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args,
+ CandidateSet,
+ /*SuppressUserConversions*/ false);
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.
@@ -12969,7 +13068,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
AddMethodTemplateCandidate(
cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC,
TemplateArgs, ObjectType, ObjectClassification, Args, CandidateSet,
- /*SuppressUsedConversions=*/false);
+ /*SuppressUserConversions=*/false);
}
}
@@ -12998,27 +13097,30 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
break;
case OR_No_Viable_Function:
- Diag(UnresExpr->getMemberLoc(),
- diag::err_ovl_no_viable_member_function_in_call)
- << DeclName << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ UnresExpr->getMemberLoc(),
+ PDiag(diag::err_ovl_no_viable_member_function_in_call)
+ << DeclName << MemExprE->getSourceRange()),
+ *this, OCD_AllCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
case OR_Ambiguous:
- Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
- << DeclName << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(UnresExpr->getMemberLoc(),
+ PDiag(diag::err_ovl_ambiguous_member_call)
+ << DeclName << MemExprE->getSourceRange()),
+ *this, OCD_AllCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
case OR_Deleted:
- Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
- << Best->Function->isDeleted()
- << DeclName
- << getDeletedOrUnavailableSuffix(Best->Function)
- << MemExprE->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(UnresExpr->getMemberLoc(),
+ PDiag(diag::err_ovl_deleted_member_call)
+ << DeclName << MemExprE->getSourceRange()),
+ *this, OCD_AllCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
}
@@ -13162,7 +13264,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
Object.get()->Classify(Context), Args, CandidateSet,
- /*SuppressUserConversions=*/false);
+ /*SuppressUserConversion=*/false);
}
// C++ [over.call.object]p2:
@@ -13222,29 +13324,35 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// below.
break;
- case OR_No_Viable_Function:
- if (CandidateSet.empty())
- Diag(Object.get()->getBeginLoc(), diag::err_ovl_no_oper)
- << Object.get()->getType() << /*call*/ 1
- << Object.get()->getSourceRange();
- else
- Diag(Object.get()->getBeginLoc(), diag::err_ovl_no_viable_object_call)
- << Object.get()->getType() << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ case OR_No_Viable_Function: {
+ PartialDiagnostic PD =
+ CandidateSet.empty()
+ ? (PDiag(diag::err_ovl_no_oper)
+ << Object.get()->getType() << /*call*/ 1
+ << Object.get()->getSourceRange())
+ : (PDiag(diag::err_ovl_no_viable_object_call)
+ << Object.get()->getType() << Object.get()->getSourceRange());
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Object.get()->getBeginLoc(), PD), *this,
+ OCD_AllCandidates, Args);
break;
-
+ }
case OR_Ambiguous:
- Diag(Object.get()->getBeginLoc(), diag::err_ovl_ambiguous_object_call)
- << Object.get()->getType() << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Object.get()->getBeginLoc(),
+ PDiag(diag::err_ovl_ambiguous_object_call)
+ << Object.get()->getType()
+ << Object.get()->getSourceRange()),
+ *this, OCD_ViableCandidates, Args);
break;
case OR_Deleted:
- Diag(Object.get()->getBeginLoc(), diag::err_ovl_deleted_object_call)
- << Best->Function->isDeleted() << Object.get()->getType()
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Object.get()->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Object.get()->getBeginLoc(),
+ PDiag(diag::err_ovl_deleted_object_call)
+ << Object.get()->getType()
+ << Object.get()->getSourceRange()),
+ *this, OCD_AllCandidates, Args);
break;
}
@@ -13268,7 +13376,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
"Found Decl & conversion-to-functionptr should be same, right?!");
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
- // on the object argument, then let ActOnCallExpr finish the job.
+ // on the object argument, then let BuildCallExpr finish the job.
// Create an implicit member expr to refer to the conversion operator.
// and then call it.
@@ -13281,7 +13389,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
CK_UserDefinedConversion, Call.get(),
nullptr, VK_RValue);
- return ActOnCallExpr(S, Call.get(), LParenLoc, Args, RParenLoc);
+ return BuildCallExpr(S, Call.get(), LParenLoc, Args, RParenLoc);
}
CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr, Best->FoundDecl);
@@ -13431,7 +13539,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
- None, CandidateSet, /*SuppressUserConversions=*/false);
+ None, CandidateSet, /*SuppressUserConversion=*/false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -13443,7 +13551,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
// Overload resolution succeeded; we'll build the call below.
break;
- case OR_No_Viable_Function:
+ case OR_No_Viable_Function: {
+ auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, Base);
if (CandidateSet.empty()) {
QualType BaseType = Base->getType();
if (NoArrowOperatorFound) {
@@ -13461,22 +13570,22 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
} else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< "operator->" << Base->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
+ CandidateSet.NoteCandidates(*this, Base, Cands);
return ExprError();
-
+ }
case OR_Ambiguous:
- Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary)
- << "->" << Base->getType() << Base->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Base);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary)
+ << "->" << Base->getType()
+ << Base->getSourceRange()),
+ *this, OCD_ViableCandidates, Base);
return ExprError();
case OR_Deleted:
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
- << "->"
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Base->getSourceRange();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
+ << "->" << Base->getSourceRange()),
+ *this, OCD_AllCandidates, Base);
return ExprError();
}
@@ -13538,14 +13647,18 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
break;
case OR_No_Viable_Function:
- Diag(UDSuffixLoc, diag::err_ovl_no_viable_function_in_call)
- << R.getLookupName();
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(UDSuffixLoc,
+ PDiag(diag::err_ovl_no_viable_function_in_call)
+ << R.getLookupName()),
+ *this, OCD_AllCandidates, Args);
return ExprError();
case OR_Ambiguous:
- Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
- CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(R.getNameLoc(), PDiag(diag::err_ovl_ambiguous_call)
+ << R.getLookupName()),
+ *this, OCD_ViableCandidates, Args);
return ExprError();
}
@@ -13615,7 +13728,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
}
- *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
+ *CallExpr = BuildCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
if (CallExpr->isInvalid()) {
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
@@ -13701,7 +13814,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
unsigned ResultIdx = GSE->getResultIndex();
AssocExprs[ResultIdx] = SubExpr;
- return new (Context) GenericSelectionExpr(
+ return GenericSelectionExpr::Create(
Context, GSE->getGenericLoc(), GSE->getControllingExpr(),
GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(),
GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(),
@@ -13775,17 +13888,10 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
TemplateArgs = &TemplateArgsBuffer;
}
- DeclRefExpr *DRE = DeclRefExpr::Create(Context,
- ULE->getQualifierLoc(),
- ULE->getTemplateKeywordLoc(),
- Fn,
- /*enclosing*/ false, // FIXME?
- ULE->getNameLoc(),
- Fn->getType(),
- VK_LValue,
- Found.getDecl(),
- TemplateArgs);
- MarkDeclRefReferenced(DRE);
+ DeclRefExpr *DRE =
+ BuildDeclRefExpr(Fn, Fn->getType(), VK_LValue, ULE->getNameInfo(),
+ ULE->getQualifierLoc(), Found.getDecl(),
+ ULE->getTemplateKeywordLoc(), TemplateArgs);
DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
return DRE;
}
@@ -13804,27 +13910,18 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
// implicit member access, rewrite to a simple decl ref.
if (MemExpr->isImplicitAccess()) {
if (cast<CXXMethodDecl>(Fn)->isStatic()) {
- DeclRefExpr *DRE = DeclRefExpr::Create(Context,
- MemExpr->getQualifierLoc(),
- MemExpr->getTemplateKeywordLoc(),
- Fn,
- /*enclosing*/ false,
- MemExpr->getMemberLoc(),
- Fn->getType(),
- VK_LValue,
- Found.getDecl(),
- TemplateArgs);
- MarkDeclRefReferenced(DRE);
+ DeclRefExpr *DRE = BuildDeclRefExpr(
+ Fn, Fn->getType(), VK_LValue, MemExpr->getNameInfo(),
+ MemExpr->getQualifierLoc(), Found.getDecl(),
+ MemExpr->getTemplateKeywordLoc(), TemplateArgs);
DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
return DRE;
} else {
SourceLocation Loc = MemExpr->getMemberLoc();
if (MemExpr->getQualifier())
Loc = MemExpr->getQualifierLoc().getBeginLoc();
- CheckCXXThisCapture(Loc);
- Base = new (Context) CXXThisExpr(Loc,
- MemExpr->getBaseType(),
- /*isImplicit=*/true);
+ Base =
+ BuildCXXThisExpr(Loc, MemExpr->getBaseType(), /*IsImplicit=*/true);
}
} else
Base = MemExpr->getBase();
@@ -13839,14 +13936,11 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
type = Context.BoundMemberTy;
}
- MemberExpr *ME = MemberExpr::Create(
- Context, Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(),
+ return BuildMemberExpr(
+ Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(),
MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found,
- MemExpr->getMemberNameInfo(), TemplateArgs, type, valueKind,
- OK_Ordinary);
- ME->setHadMultipleCandidates(true);
- MarkMemberReferenced(ME);
- return ME;
+ /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(),
+ type, valueKind, OK_Ordinary, TemplateArgs);
}
llvm_unreachable("Invalid reference to overloaded function");
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index ebf1d10aa16a..06bcd8d00ded 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -1,9 +1,8 @@
//===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -141,25 +140,24 @@ namespace {
unsigned resultIndex = gse->getResultIndex();
unsigned numAssocs = gse->getNumAssocs();
- SmallVector<Expr*, 8> assocs(numAssocs);
- SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs);
-
- for (unsigned i = 0; i != numAssocs; ++i) {
- Expr *assoc = gse->getAssocExpr(i);
- if (i == resultIndex) assoc = rebuild(assoc);
- assocs[i] = assoc;
- assocTypes[i] = gse->getAssocTypeSourceInfo(i);
+ SmallVector<Expr *, 8> assocExprs;
+ SmallVector<TypeSourceInfo *, 8> assocTypes;
+ assocExprs.reserve(numAssocs);
+ assocTypes.reserve(numAssocs);
+
+ for (const GenericSelectionExpr::Association &assoc :
+ gse->associations()) {
+ Expr *assocExpr = assoc.getAssociationExpr();
+ if (assoc.isSelected())
+ assocExpr = rebuild(assocExpr);
+ assocExprs.push_back(assocExpr);
+ assocTypes.push_back(assoc.getTypeSourceInfo());
}
- return new (S.Context) GenericSelectionExpr(S.Context,
- gse->getGenericLoc(),
- gse->getControllingExpr(),
- assocTypes,
- assocs,
- gse->getDefaultLoc(),
- gse->getRParenLoc(),
- gse->containsUnexpandedParameterPack(),
- resultIndex);
+ return GenericSelectionExpr::Create(
+ S.Context, gse->getGenericLoc(), gse->getControllingExpr(),
+ assocTypes, assocExprs, gse->getDefaultLoc(), gse->getRParenLoc(),
+ gse->containsUnexpandedParameterPack(), resultIndex);
}
if (ChooseExpr *ce = dyn_cast<ChooseExpr>(e)) {
@@ -1493,7 +1491,7 @@ ExprResult MSPropertyOpBuilder::buildGet() {
return ExprError();
}
- return S.ActOnCallExpr(S.getCurScope(), GetterExpr.get(),
+ return S.BuildCallExpr(S.getCurScope(), GetterExpr.get(),
RefExpr->getSourceRange().getBegin(), CallArgs,
RefExpr->getSourceRange().getEnd());
}
@@ -1525,7 +1523,7 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
SmallVector<Expr*, 4> ArgExprs;
ArgExprs.append(CallArgs.begin(), CallArgs.end());
ArgExprs.push_back(op);
- return S.ActOnCallExpr(S.getCurScope(), SetterExpr.get(),
+ return S.BuildCallExpr(S.getCurScope(), SetterExpr.get(),
RefExpr->getSourceRange().getBegin(), ArgExprs,
op->getSourceRange().getEnd());
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 9e30c9a396c0..480155df8990 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1,9 +1,8 @@
//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -11,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
@@ -347,10 +347,6 @@ sema::CompoundScopeInfo &Sema::getCurCompoundScope() const {
return getCurFunction()->CompoundScopes.back();
}
-bool Sema::isCurCompoundStmtAStmtExpr() const {
- return getCurCompoundScope().IsStmtExpr;
-}
-
StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
@@ -943,7 +939,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
bool ShouldCheckConstantCond = HasConstantCond;
// Sort all the scalar case values so we can easily detect duplicates.
- std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals);
+ llvm::stable_sort(CaseVals, CmpCaseVals);
if (!CaseVals.empty()) {
for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) {
@@ -991,7 +987,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
if (!CaseRanges.empty()) {
// Sort all the case ranges by their low value so we can easily detect
// overlaps between ranges.
- std::stable_sort(CaseRanges.begin(), CaseRanges.end());
+ llvm::stable_sort(CaseRanges);
// Scan the ranges, computing the high values and removing empty ranges.
std::vector<llvm::APSInt> HiVals;
@@ -1045,9 +1041,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Find the smallest value >= the lower bound. If I is in the
// case range, then we have overlap.
- CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(),
- CaseVals.end(), CRLo,
- CaseCompareFunctor());
+ CaseValsTy::iterator I =
+ llvm::lower_bound(CaseVals, CRLo, CaseCompareFunctor());
if (I != CaseVals.end() && I->first < CRHi) {
OverlapVal = I->first; // Found overlap with scalar.
OverlapStmt = I->second;
@@ -1110,7 +1105,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
AdjustAPSInt(Val, CondWidth, CondIsSigned);
EnumVals.push_back(std::make_pair(Val, EDI));
}
- std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ llvm::stable_sort(EnumVals, CmpEnumVals);
auto EI = EnumVals.begin(), EIEnd =
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
@@ -1167,6 +1162,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
break;
}
+ if (EI->second->hasAttr<UnusedAttr>())
+ continue;
+
// Drop unneeded case values
while (CI != CaseVals.end() && CI->first < EI->first)
CI++;
@@ -1261,7 +1259,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
}
if (EnumVals.empty())
return;
- std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ llvm::stable_sort(EnumVals, CmpEnumVals);
EnumValsTy::iterator EIend =
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
@@ -2229,9 +2227,11 @@ BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
return Sema::FRS_Success;
case Sema::FRS_NoViableFunction:
- SemaRef.Diag(BeginRange->getBeginLoc(), diag::err_for_range_invalid)
- << BeginRange->getType() << BEFFound;
- CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, BeginRange);
+ CandidateSet->NoteCandidates(
+ PartialDiagnosticAt(BeginRange->getBeginLoc(),
+ SemaRef.PDiag(diag::err_for_range_invalid)
+ << BeginRange->getType() << BEFFound),
+ SemaRef, OCD_AllCandidates, BeginRange);
LLVM_FALLTHROUGH;
case Sema::FRS_DiagnosticIssued:
@@ -2447,7 +2447,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
EndVar->getLocation(), UETT_SizeOf,
- /*isType=*/true,
+ /*IsType=*/true,
CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
VAT->desugar(), RangeLoc))
.getAsOpaquePtr(),
@@ -2457,7 +2457,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
EndVar->getLocation(), UETT_SizeOf,
- /*isType=*/true,
+ /*IsType=*/true,
CreateParsedType(VAT->desugar(),
Context.getTrivialTypeSourceInfo(
VAT->getElementType(), RangeLoc))
@@ -2528,9 +2528,12 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
// Otherwise, emit diagnostics if we haven't already.
if (RangeStatus == FRS_NoViableFunction) {
Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
- Diag(Range->getBeginLoc(), diag::err_for_range_invalid)
- << RangeLoc << Range->getType() << BEFFailure;
- CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Range);
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Range->getBeginLoc(),
+ PDiag(diag::err_for_range_invalid)
+ << RangeLoc << Range->getType()
+ << BEFFailure),
+ *this, OCD_AllCandidates, Range);
}
// Return an error if no fix was discovered.
if (RangeStatus != FRS_Success)
@@ -3387,10 +3390,10 @@ bool LocalTypedefNameReferencer::VisitRecordType(const RecordType *RT) {
}
TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
- TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
- while (auto ATL = TL.getAs<AttributedTypeLoc>())
- TL = ATL.getModifiedLoc().IgnoreParens();
- return TL.castAs<FunctionProtoTypeLoc>().getReturnLoc();
+ return FD->getTypeSourceInfo()
+ ->getTypeLoc()
+ .getAsAdjusted<FunctionProtoTypeLoc>()
+ .getReturnLoc();
}
/// Deduce the return type for a function from a returned expression, per
@@ -3500,7 +3503,12 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
StmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Scope *CurScope) {
- StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp);
+ // Correct typos, in case the containing function returns 'auto' and
+ // RetValExp should determine the deduced type.
+ ExprResult RetVal = CorrectDelayedTyposInExpr(RetValExp);
+ if (RetVal.isInvalid())
+ return StmtError();
+ StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get());
if (R.isInvalid() || ExprEvalContexts.back().Context ==
ExpressionEvaluationContext::DiscardedStatement)
return R;
@@ -3684,7 +3692,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (FD)
- Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/;
+ Diag(ReturnLoc, DiagID)
+ << FD->getIdentifier() << 0 /*fn*/ << FD->isConsteval();
else
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
@@ -3998,12 +4007,10 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
ArrayRef<Stmt *> Handlers) {
// Don't report an error if 'try' is used in system headers.
if (!getLangOpts().CXXExceptions &&
- !getSourceManager().isInSystemHeader(TryLoc) &&
- (!getLangOpts().OpenMPIsDevice ||
- !getLangOpts().OpenMPHostCXXExceptions ||
- isInOpenMPTargetExecutionDirective() ||
- isInOpenMPDeclareTargetContext()))
- Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+ !getSourceManager().isInSystemHeader(TryLoc) && !getLangOpts().CUDA) {
+ // Delay error emission for the OpenMP device code.
+ targetDiag(TryLoc, diag::err_exceptions_disabled) << "try";
+ }
// Exceptions aren't allowed in CUDA device code.
if (getLangOpts().CUDA)
@@ -4216,30 +4223,46 @@ Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc,
return RD;
}
-static void
-buildCapturedStmtCaptureList(SmallVectorImpl<CapturedStmt::Capture> &Captures,
- SmallVectorImpl<Expr *> &CaptureInits,
- ArrayRef<sema::Capture> Candidates) {
- for (const sema::Capture &Cap : Candidates) {
+static bool
+buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
+ SmallVectorImpl<CapturedStmt::Capture> &Captures,
+ SmallVectorImpl<Expr *> &CaptureInits) {
+ for (const sema::Capture &Cap : RSI->Captures) {
+ if (Cap.isInvalid())
+ continue;
+
+ // Form the initializer for the capture.
+ ExprResult Init = S.BuildCaptureInit(Cap, Cap.getLocation(),
+ RSI->CapRegionKind == CR_OpenMP);
+
+ // FIXME: Bail out now if the capture is not used and the initializer has
+ // no side-effects.
+
+ // Create a field for this capture.
+ FieldDecl *Field = S.BuildCaptureField(RSI->TheRecordDecl, Cap);
+
+ // Add the capture to our list of captures.
if (Cap.isThisCapture()) {
Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
CapturedStmt::VCK_This));
- CaptureInits.push_back(Cap.getInitExpr());
- continue;
} else if (Cap.isVLATypeCapture()) {
Captures.push_back(
CapturedStmt::Capture(Cap.getLocation(), CapturedStmt::VCK_VLAType));
- CaptureInits.push_back(nullptr);
- continue;
- }
+ } else {
+ assert(Cap.isVariableCapture() && "unknown kind of capture");
- Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
- Cap.isReferenceCapture()
- ? CapturedStmt::VCK_ByRef
- : CapturedStmt::VCK_ByCopy,
- Cap.getVariable()));
- CaptureInits.push_back(Cap.getInitExpr());
+ if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
+ S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
+
+ Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
+ Cap.isReferenceCapture()
+ ? CapturedStmt::VCK_ByRef
+ : CapturedStmt::VCK_ByCopy,
+ Cap.getVariable()));
+ }
+ CaptureInits.push_back(Init.get());
}
+ return false;
}
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
@@ -4332,25 +4355,31 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
void Sema::ActOnCapturedRegionError() {
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
+ PopDeclContext();
+ PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo();
+ CapturedRegionScopeInfo *RSI = cast<CapturedRegionScopeInfo>(ScopeRAII.get());
- CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
RecordDecl *Record = RSI->TheRecordDecl;
Record->setInvalidDecl();
SmallVector<Decl*, 4> Fields(Record->fields());
ActOnFields(/*Scope=*/nullptr, Record->getLocation(), Record, Fields,
SourceLocation(), SourceLocation(), ParsedAttributesView());
-
- PopDeclContext();
- PopFunctionScopeInfo();
}
StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
- CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
+ // Leave the captured scope before we start creating captures in the
+ // enclosing scope.
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+ PopDeclContext();
+ PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo();
+ CapturedRegionScopeInfo *RSI = cast<CapturedRegionScopeInfo>(ScopeRAII.get());
SmallVector<CapturedStmt::Capture, 4> Captures;
SmallVector<Expr *, 4> CaptureInits;
- buildCapturedStmtCaptureList(Captures, CaptureInits, RSI->Captures);
+ if (buildCapturedStmtCaptureList(*this, RSI, Captures, CaptureInits))
+ return StmtError();
CapturedDecl *CD = RSI->TheCapturedDecl;
RecordDecl *RD = RSI->TheRecordDecl;
@@ -4362,11 +4391,5 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
CD->setBody(Res->getCapturedStmt());
RD->completeDefinition();
- DiscardCleanupsInEvaluationContext();
- PopExpressionEvaluationContext();
-
- PopDeclContext();
- PopFunctionScopeInfo();
-
return Res;
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 9e084c99d0dd..b123a739a7ab 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -1,9 +1,8 @@
//===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -210,11 +209,12 @@ static StringRef extractRegisterName(const Expr *Expression,
static SourceLocation
getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
StringLiteral **Clobbers, int NumClobbers,
+ unsigned NumLabels,
const TargetInfo &Target, ASTContext &Cont) {
llvm::StringSet<> InOutVars;
// Collect all the input and output registers from the extended asm
// statement in order to check for conflicts with the clobber list
- for (unsigned int i = 0; i < Exprs.size(); ++i) {
+ for (unsigned int i = 0; i < Exprs.size() - NumLabels; ++i) {
StringRef Constraint = Constraints[i]->getString();
StringRef InOutReg = Target.getConstraintRegister(
Constraint, extractRegisterName(Exprs[i], Target));
@@ -242,6 +242,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
unsigned NumInputs, IdentifierInfo **Names,
MultiExprArg constraints, MultiExprArg Exprs,
Expr *asmString, MultiExprArg clobbers,
+ unsigned NumLabels,
SourceLocation RParenLoc) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
@@ -254,15 +255,6 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// The parser verifies that there is a string literal here.
assert(AsmString->isAscii());
- // If we're compiling CUDA file and function attributes indicate that it's not
- // for this compilation side, skip all the checks.
- if (!DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) {
- GCCAsmStmt *NS = new (Context) GCCAsmStmt(
- Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names,
- Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc);
- return NS;
- }
-
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
assert(Literal->isAscii());
@@ -272,10 +264,15 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
OutputName = Names[i]->getName();
TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
- if (!Context.getTargetInfo().validateOutputConstraint(Info))
- return StmtError(
- Diag(Literal->getBeginLoc(), diag::err_asm_invalid_output_constraint)
- << Info.getConstraintStr());
+ if (!Context.getTargetInfo().validateOutputConstraint(Info)) {
+ targetDiag(Literal->getBeginLoc(),
+ diag::err_asm_invalid_output_constraint)
+ << Info.getConstraintStr();
+ return new (Context)
+ GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs.data(), AsmString,
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
+ }
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
if (ER.isInvalid())
@@ -329,10 +326,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
unsigned Size = Context.getTypeSize(OutputExpr->getType());
if (!Context.getTargetInfo().validateOutputSize(Literal->getString(),
- Size))
- return StmtError(
- Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
- << Info.getConstraintStr());
+ Size)) {
+ targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
+ << Info.getConstraintStr();
+ return new (Context)
+ GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs.data(), AsmString,
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
+ }
}
SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
@@ -348,9 +349,12 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos,
Info)) {
- return StmtError(
- Diag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint)
- << Info.getConstraintStr());
+ targetDiag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint)
+ << Info.getConstraintStr();
+ return new (Context)
+ GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs.data(), AsmString,
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
}
ExprResult ER = CheckPlaceholderExpr(Exprs[i]);
@@ -383,11 +387,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return StmtError(
Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
<< Info.getConstraintStr() << InputExpr->getSourceRange());
- llvm::APSInt Result = EVResult.Val.getInt();
- if (!Info.isValidAsmImmediate(Result))
+
+ // For compatibility with GCC, we also allow pointers that would be
+ // integral constant expressions if they were cast to int.
+ llvm::APSInt IntResult;
+ if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
+ Context))
+ return StmtError(
+ Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
+ << Info.getConstraintStr() << InputExpr->getSourceRange());
+
+ if (!Info.isValidAsmImmediate(IntResult))
return StmtError(Diag(InputExpr->getBeginLoc(),
diag::err_invalid_asm_value_for_constraint)
- << Result.toString(10) << Info.getConstraintStr()
+ << IntResult.toString(10) << Info.getConstraintStr()
<< InputExpr->getSourceRange());
}
@@ -422,8 +435,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
unsigned Size = Context.getTypeSize(Ty);
if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
Size))
- return StmtError(
- Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size)
+ return StmtResult(
+ targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size)
<< Info.getConstraintStr());
}
@@ -434,24 +447,29 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
StringRef Clobber = Literal->getString();
- if (!Context.getTargetInfo().isValidClobber(Clobber))
- return StmtError(
- Diag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name)
- << Clobber);
+ if (!Context.getTargetInfo().isValidClobber(Clobber)) {
+ targetDiag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name)
+ << Clobber;
+ return new (Context)
+ GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
+ NumInputs, Names, Constraints, Exprs.data(), AsmString,
+ NumClobbers, Clobbers, NumLabels, RParenLoc);
+ }
}
GCCAsmStmt *NS =
new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(),
- AsmString, NumClobbers, Clobbers, RParenLoc);
+ AsmString, NumClobbers, Clobbers, NumLabels,
+ RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
unsigned DiagOffs;
if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
- Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
- << AsmString->getSourceRange();
- return StmtError();
+ targetDiag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
+ << AsmString->getSourceRange();
+ return NS;
}
// Validate constraints and modifiers.
@@ -461,8 +479,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Look for the correct constraint index.
unsigned ConstraintIdx = Piece.getOperandNo();
+ // Labels are the last in the Exprs list.
+ if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs())
+ continue;
unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs();
-
// Look for the (ConstraintIdx - NumOperands + 1)th constraint with
// modifier '+'.
if (ConstraintIdx >= NumOperands) {
@@ -489,16 +509,15 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (!Context.getTargetInfo().validateConstraintModifier(
Literal->getString(), Piece.getModifier(), Size,
SuggestedModifier)) {
- Diag(Exprs[ConstraintIdx]->getBeginLoc(),
- diag::warn_asm_mismatched_size_modifier);
+ targetDiag(Exprs[ConstraintIdx]->getBeginLoc(),
+ diag::warn_asm_mismatched_size_modifier);
if (!SuggestedModifier.empty()) {
- auto B = Diag(Piece.getRange().getBegin(),
- diag::note_asm_missing_constraint_modifier)
+ auto B = targetDiag(Piece.getRange().getBegin(),
+ diag::note_asm_missing_constraint_modifier)
<< SuggestedModifier;
SuggestedModifier = "%" + SuggestedModifier + Piece.getString();
- B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(),
- SuggestedModifier));
+ B << FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier);
}
}
}
@@ -509,12 +528,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
StringRef ConstraintStr = Info.getConstraintStr();
unsigned AltCount = ConstraintStr.count(',') + 1;
- if (NumAlternatives == ~0U)
+ if (NumAlternatives == ~0U) {
NumAlternatives = AltCount;
- else if (NumAlternatives != AltCount)
- return StmtError(Diag(NS->getOutputExpr(i)->getBeginLoc(),
- diag::err_asm_unexpected_constraint_alternatives)
- << NumAlternatives << AltCount);
+ } else if (NumAlternatives != AltCount) {
+ targetDiag(NS->getOutputExpr(i)->getBeginLoc(),
+ diag::err_asm_unexpected_constraint_alternatives)
+ << NumAlternatives << AltCount;
+ return NS;
+ }
}
SmallVector<size_t, 4> InputMatchedToOutput(OutputConstraintInfos.size(),
~0U);
@@ -522,12 +543,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
StringRef ConstraintStr = Info.getConstraintStr();
unsigned AltCount = ConstraintStr.count(',') + 1;
- if (NumAlternatives == ~0U)
+ if (NumAlternatives == ~0U) {
NumAlternatives = AltCount;
- else if (NumAlternatives != AltCount)
- return StmtError(Diag(NS->getInputExpr(i)->getBeginLoc(),
- diag::err_asm_unexpected_constraint_alternatives)
- << NumAlternatives << AltCount);
+ } else if (NumAlternatives != AltCount) {
+ targetDiag(NS->getInputExpr(i)->getBeginLoc(),
+ diag::err_asm_unexpected_constraint_alternatives)
+ << NumAlternatives << AltCount;
+ return NS;
+ }
// If this is a tied constraint, verify that the output and input have
// either exactly the same type, or that they are int/ptr operands with the
@@ -542,13 +565,13 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Make sure no more than one input constraint matches each output.
assert(TiedTo < InputMatchedToOutput.size() && "TiedTo value out of range");
if (InputMatchedToOutput[TiedTo] != ~0U) {
- Diag(NS->getInputExpr(i)->getBeginLoc(),
- diag::err_asm_input_duplicate_match)
+ targetDiag(NS->getInputExpr(i)->getBeginLoc(),
+ diag::err_asm_input_duplicate_match)
<< TiedTo;
- Diag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(),
- diag::note_asm_input_duplicate_first)
+ targetDiag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(),
+ diag::note_asm_input_duplicate_first)
<< TiedTo;
- return StmtError();
+ return NS;
}
InputMatchedToOutput[TiedTo] = i;
@@ -633,19 +656,48 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
continue;
}
- Diag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types)
+ targetDiag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
<< InputExpr->getSourceRange();
- return StmtError();
+ return NS;
}
// Check for conflicts between clobber list and input or output lists
SourceLocation ConstraintLoc =
getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers,
+ NumLabels,
Context.getTargetInfo(), Context);
if (ConstraintLoc.isValid())
- return Diag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber);
+ targetDiag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber);
+ // Check for duplicate asm operand name between input, output and label lists.
+ typedef std::pair<StringRef , Expr *> NamedOperand;
+ SmallVector<NamedOperand, 4> NamedOperandList;
+ for (unsigned i = 0, e = NumOutputs + NumInputs + NumLabels; i != e; ++i)
+ if (Names[i])
+ NamedOperandList.emplace_back(
+ std::make_pair(Names[i]->getName(), Exprs[i]));
+ // Sort NamedOperandList.
+ std::stable_sort(NamedOperandList.begin(), NamedOperandList.end(),
+ [](const NamedOperand &LHS, const NamedOperand &RHS) {
+ return LHS.first < RHS.first;
+ });
+ // Find adjacent duplicate operand.
+ SmallVector<NamedOperand, 4>::iterator Found =
+ std::adjacent_find(begin(NamedOperandList), end(NamedOperandList),
+ [](const NamedOperand &LHS, const NamedOperand &RHS) {
+ return LHS.first == RHS.first;
+ });
+ if (Found != NamedOperandList.end()) {
+ Diag((Found + 1)->second->getBeginLoc(),
+ diag::error_duplicate_asm_operand_name)
+ << (Found + 1)->first;
+ Diag(Found->second->getBeginLoc(), diag::note_duplicate_asm_operand_name)
+ << Found->first;
+ return StmtError();
+ }
+ if (NS->isAsmGoto())
+ setFunctionHasBranchIntoScope();
return NS;
}
@@ -797,7 +849,7 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
return CXXDependentScopeMemberExpr::Create(
Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(),
SourceLocation(),
- /*FirstQualifierInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
+ /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
}
const RecordType *RT = T->getAs<RecordType>();
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index a8e54b36b29b..791c52c2d913 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -1,9 +1,8 @@
//===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -83,22 +82,17 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
IdentifierLoc *StateLoc = A.getArgAsIdent(2);
Expr *ValueExpr = A.getArgAsExpr(3);
- bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
- bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
- bool PragmaUnrollAndJam = PragmaNameLoc->Ident->getName() == "unroll_and_jam";
- bool PragmaNoUnrollAndJam =
- PragmaNameLoc->Ident->getName() == "nounroll_and_jam";
+ StringRef PragmaName =
+ llvm::StringSwitch<StringRef>(PragmaNameLoc->Ident->getName())
+ .Cases("unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam",
+ PragmaNameLoc->Ident->getName())
+ .Default("clang loop");
+
if (St->getStmtClass() != Stmt::DoStmtClass &&
St->getStmtClass() != Stmt::ForStmtClass &&
St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
St->getStmtClass() != Stmt::WhileStmtClass) {
- const char *Pragma =
- llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
- .Case("unroll", "#pragma unroll")
- .Case("nounroll", "#pragma nounroll")
- .Case("unroll_and_jam", "#pragma unroll_and_jam")
- .Case("nounroll_and_jam", "#pragma nounroll_and_jam")
- .Default("#pragma clang loop");
+ std::string Pragma = "#pragma " + std::string(PragmaName);
S.Diag(St->getBeginLoc(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
return nullptr;
}
@@ -107,34 +101,29 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
LoopHintAttr::Spelling(A.getAttributeSpellingListIndex());
LoopHintAttr::OptionType Option;
LoopHintAttr::LoopHintState State;
- if (PragmaNoUnroll) {
- // #pragma nounroll
- Option = LoopHintAttr::Unroll;
- State = LoopHintAttr::Disable;
- } else if (PragmaUnroll) {
- if (ValueExpr) {
- // #pragma unroll N
- Option = LoopHintAttr::UnrollCount;
- State = LoopHintAttr::Numeric;
- } else {
- // #pragma unroll
- Option = LoopHintAttr::Unroll;
- State = LoopHintAttr::Enable;
- }
- } else if (PragmaNoUnrollAndJam) {
- // #pragma nounroll_and_jam
- Option = LoopHintAttr::UnrollAndJam;
- State = LoopHintAttr::Disable;
- } else if (PragmaUnrollAndJam) {
- if (ValueExpr) {
- // #pragma unroll_and_jam N
- Option = LoopHintAttr::UnrollAndJamCount;
- State = LoopHintAttr::Numeric;
- } else {
- // #pragma unroll_and_jam
- Option = LoopHintAttr::UnrollAndJam;
- State = LoopHintAttr::Enable;
- }
+
+ auto SetHints = [&Option, &State](LoopHintAttr::OptionType O,
+ LoopHintAttr::LoopHintState S) {
+ Option = O;
+ State = S;
+ };
+
+ if (PragmaName == "nounroll") {
+ SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
+ } else if (PragmaName == "unroll") {
+ // #pragma unroll N
+ if (ValueExpr)
+ SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
+ else
+ SetHints(LoopHintAttr::Unroll, LoopHintAttr::Enable);
+ } else if (PragmaName == "nounroll_and_jam") {
+ SetHints(LoopHintAttr::UnrollAndJam, LoopHintAttr::Disable);
+ } else if (PragmaName == "unroll_and_jam") {
+ // #pragma unroll_and_jam N
+ if (ValueExpr)
+ SetHints(LoopHintAttr::UnrollAndJamCount, LoopHintAttr::Numeric);
+ else
+ SetHints(LoopHintAttr::UnrollAndJam, LoopHintAttr::Enable);
} else {
// #pragma clang loop ...
assert(OptionLoc && OptionLoc->Ident &&
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3f9dc989103f..3212281cc34d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1,9 +1,8 @@
//===------- 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.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for C++ templates.
@@ -67,17 +66,20 @@ static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params,
/// Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
-/// returns NULL.
-static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
- NamedDecl *Orig,
- bool AllowFunctionTemplates) {
- NamedDecl *D = Orig->getUnderlyingDecl();
+/// returns null.
+///
+/// Note that this may return an UnresolvedUsingValueDecl if AllowDependent
+/// is true. In all other cases it will return a TemplateDecl (or null).
+NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
+ bool AllowFunctionTemplates,
+ bool AllowDependent) {
+ D = D->getUnderlyingDecl();
if (isa<TemplateDecl>(D)) {
if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D))
return nullptr;
- return Orig;
+ return D;
}
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
@@ -108,55 +110,35 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
// 'using Dependent::foo;' can resolve to a template name.
// 'using typename Dependent::foo;' cannot (not even if 'foo' is an
// injected-class-name).
- if (isa<UnresolvedUsingValueDecl>(D))
+ if (AllowDependent && isa<UnresolvedUsingValueDecl>(D))
return D;
return nullptr;
}
void Sema::FilterAcceptableTemplateNames(LookupResult &R,
- bool AllowFunctionTemplates) {
- // The set of class templates we've already seen.
- llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
+ bool AllowFunctionTemplates,
+ bool AllowDependent) {
LookupResult::Filter filter = R.makeFilter();
while (filter.hasNext()) {
NamedDecl *Orig = filter.next();
- NamedDecl *Repl = isAcceptableTemplateName(Context, Orig,
- AllowFunctionTemplates);
- if (!Repl)
+ if (!getAsTemplateNameDecl(Orig, AllowFunctionTemplates, AllowDependent))
filter.erase();
- else if (Repl != Orig) {
-
- // C++ [temp.local]p3:
- // A lookup that finds an injected-class-name (10.2) can result in an
- // ambiguity in certain cases (for example, if it is found in more than
- // one base class). If all of the injected-class-names that are found
- // refer to specializations of the same class template, and if the name
- // is used as a template-name, the reference refers to the class
- // template itself and not a specialization thereof, and is not
- // ambiguous.
- if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
- if (!ClassTemplates.insert(ClassTmpl).second) {
- filter.erase();
- continue;
- }
-
- // FIXME: we promote access to public here as a workaround to
- // the fact that LookupResult doesn't let us remember that we
- // found this template through a particular injected class name,
- // which means we end up doing nasty things to the invariants.
- // Pretending that access is public is *much* safer.
- filter.replace(Repl, AS_public);
- }
}
filter.done();
}
bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,
- bool AllowFunctionTemplates) {
- for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)
- if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates))
+ bool AllowFunctionTemplates,
+ bool AllowDependent,
+ bool AllowNonTemplateFunctions) {
+ for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) {
+ if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent))
+ return true;
+ if (AllowNonTemplateFunctions &&
+ isa<FunctionDecl>((*I)->getUnderlyingDecl()))
return true;
+ }
return false;
}
@@ -194,25 +176,64 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
QualType ObjectType = ObjectTypePtr.get();
+ AssumedTemplateKind AssumedTemplate;
LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
- MemberOfUnknownSpecialization))
+ MemberOfUnknownSpecialization, SourceLocation(),
+ &AssumedTemplate))
return TNK_Non_template;
- if (R.empty()) return TNK_Non_template;
- if (R.isAmbiguous()) {
- // Suppress diagnostics; we'll redo this lookup later.
- R.suppressDiagnostics();
- // FIXME: we might have ambiguous templates, in which case we
- // should at least parse them properly!
+ if (AssumedTemplate != AssumedTemplateKind::None) {
+ TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName));
+ // Let the parser know whether we found nothing or found functions; if we
+ // found nothing, we want to more carefully check whether this is actually
+ // a function template name versus some other kind of undeclared identifier.
+ return AssumedTemplate == AssumedTemplateKind::FoundNothing
+ ? TNK_Undeclared_template
+ : TNK_Function_template;
+ }
+
+ if (R.empty())
return TNK_Non_template;
+
+ NamedDecl *D = nullptr;
+ if (R.isAmbiguous()) {
+ // If we got an ambiguity involving a non-function template, treat this
+ // as a template name, and pick an arbitrary template for error recovery.
+ bool AnyFunctionTemplates = false;
+ for (NamedDecl *FoundD : R) {
+ if (NamedDecl *FoundTemplate = getAsTemplateNameDecl(FoundD)) {
+ if (isa<FunctionTemplateDecl>(FoundTemplate))
+ AnyFunctionTemplates = true;
+ else {
+ D = FoundTemplate;
+ break;
+ }
+ }
+ }
+
+ // If we didn't find any templates at all, this isn't a template name.
+ // Leave the ambiguity for a later lookup to diagnose.
+ if (!D && !AnyFunctionTemplates) {
+ R.suppressDiagnostics();
+ return TNK_Non_template;
+ }
+
+ // If the only templates were function templates, filter out the rest.
+ // We'll diagnose the ambiguity later.
+ if (!D)
+ FilterAcceptableTemplateNames(R);
}
+ // At this point, we have either picked a single template name declaration D
+ // or we have a non-empty set of results R containing either one template name
+ // declaration or a set of function templates.
+
TemplateName Template;
TemplateNameKind TemplateKind;
unsigned ResultCount = R.end() - R.begin();
- if (ResultCount > 1) {
+ if (!D && ResultCount > 1) {
// We assume that we'll preserve the qualifier from a function
// template name in other ways.
Template = Context.getOverloadedTemplateName(R.begin(), R.end());
@@ -220,12 +241,19 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// We'll do this lookup again later.
R.suppressDiagnostics();
- } else if (isa<UnresolvedUsingValueDecl>((*R.begin())->getUnderlyingDecl())) {
- // We don't yet know whether this is a template-name or not.
- MemberOfUnknownSpecialization = true;
- return TNK_Non_template;
} else {
- TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl());
+ if (!D) {
+ D = getAsTemplateNameDecl(*R.begin());
+ assert(D && "unambiguous result is not a template name");
+ }
+
+ if (isa<UnresolvedUsingValueDecl>(D)) {
+ // We don't yet know whether this is a template-name or not.
+ MemberOfUnknownSpecialization = true;
+ return TNK_Non_template;
+ }
+
+ TemplateDecl *TD = cast<TemplateDecl>(D);
if (SS.isSet() && !SS.isInvalid()) {
NestedNameSpecifier *Qualifier = SS.getScopeRep();
@@ -243,9 +271,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
- isa<BuiltinTemplateDecl>(TD));
+ isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));
TemplateKind =
- isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
+ isa<VarTemplateDecl>(TD) ? TNK_Var_template :
+ isa<ConceptDecl>(TD) ? TNK_Concept_template :
+ TNK_Type_template;
}
}
@@ -316,7 +346,13 @@ bool Sema::LookupTemplateName(LookupResult &Found,
QualType ObjectType,
bool EnteringContext,
bool &MemberOfUnknownSpecialization,
- SourceLocation TemplateKWLoc) {
+ SourceLocation TemplateKWLoc,
+ AssumedTemplateKind *ATK) {
+ if (ATK)
+ *ATK = AssumedTemplateKind::None;
+
+ Found.setTemplateNameLookup(true);
+
// Determine where to perform name lookup
MemberOfUnknownSpecialization = false;
DeclContext *LookupCtx = nullptr;
@@ -391,24 +427,55 @@ bool Sema::LookupTemplateName(LookupResult &Found,
IsDependent |= Found.wasNotFoundInCurrentInstantiation();
}
+ if (Found.isAmbiguous())
+ return false;
+
+ if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) {
+ // C++2a [temp.names]p2:
+ // A name is also considered to refer to a template if it is an
+ // unqualified-id followed by a < and name lookup finds either one or more
+ // functions or finds nothing.
+ //
+ // To keep our behavior consistent, we apply the "finds nothing" part in
+ // all language modes, and diagnose the empty lookup in ActOnCallExpr if we
+ // successfully form a call to an undeclared template-id.
+ bool AllFunctions =
+ getLangOpts().CPlusPlus2a &&
+ std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) {
+ return isa<FunctionDecl>(ND->getUnderlyingDecl());
+ });
+ if (AllFunctions || (Found.empty() && !IsDependent)) {
+ // If lookup found any functions, or if this is a name that can only be
+ // used for a function, then strongly assume this is a function
+ // template-id.
+ *ATK = (Found.empty() && Found.getLookupName().isIdentifier())
+ ? AssumedTemplateKind::FoundNothing
+ : AssumedTemplateKind::FoundFunctions;
+ Found.clear();
+ return false;
+ }
+ }
+
if (Found.empty() && !IsDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
// Simple filter callback that, for keywords, only accepts the C++ *_cast
- auto FilterCCC = llvm::make_unique<CorrectionCandidateCallback>();
- FilterCCC->WantTypeSpecifiers = false;
- FilterCCC->WantExpressionKeywords = false;
- FilterCCC->WantRemainingKeywords = false;
- FilterCCC->WantCXXNamedCasts = true;
- if (TypoCorrection Corrected = CorrectTypo(
- Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS,
- std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) {
- Found.setLookupName(Corrected.getCorrection());
+ DefaultFilterCCC FilterCCC{};
+ FilterCCC.WantTypeSpecifiers = false;
+ FilterCCC.WantExpressionKeywords = false;
+ FilterCCC.WantRemainingKeywords = false;
+ FilterCCC.WantCXXNamedCasts = true;
+ if (TypoCorrection Corrected =
+ CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,
+ &SS, FilterCCC, CTK_ErrorRecovery, LookupCtx)) {
if (auto *ND = Corrected.getFoundDecl())
Found.addDecl(ND);
FilterAcceptableTemplateNames(Found);
- if (!Found.empty()) {
+ if (Found.isAmbiguous()) {
+ Found.clear();
+ } else if (!Found.empty()) {
+ Found.setLookupName(Corrected.getCorrection());
if (LookupCtx) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
@@ -420,8 +487,6 @@ bool Sema::LookupTemplateName(LookupResult &Found,
diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) << Name);
}
}
- } else {
- Found.setLookupName(Name);
}
}
@@ -458,14 +523,19 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// Note: C++11 does not perform this second lookup.
LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
LookupOrdinaryName);
+ FoundOuter.setTemplateNameLookup(true);
LookupName(FoundOuter, S);
+ // FIXME: We silently accept an ambiguous lookup here, in violation of
+ // [basic.lookup]/1.
FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false);
+ NamedDecl *OuterTemplate;
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
// object expression is used, otherwise
- } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() ||
- FoundOuter.isAmbiguous()) {
+ } else if (FoundOuter.isAmbiguous() || !FoundOuter.isSingleResult() ||
+ !(OuterTemplate =
+ getAsTemplateNameDecl(FoundOuter.getFoundDecl()))) {
// - if the name is found in the context of the entire
// postfix-expression and does not name a class template, the name
// found in the class of the object expression is used, otherwise
@@ -475,8 +545,8 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// entity as the one found in the class of the object expression,
// otherwise the program is ill-formed.
if (!Found.isSingleResult() ||
- Found.getFoundDecl()->getCanonicalDecl()
- != FoundOuter.getFoundDecl()->getCanonicalDecl()) {
+ getAsTemplateNameDecl(Found.getFoundDecl())->getCanonicalDecl() !=
+ OuterTemplate->getCanonicalDecl()) {
Diag(Found.getNameLoc(),
diag::ext_nested_name_member_ref_lookup_ambiguous)
<< Found.getLookupName()
@@ -546,7 +616,8 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
// Try to correct the name by looking for templates and C++ named casts.
struct TemplateCandidateFilter : CorrectionCandidateCallback {
- TemplateCandidateFilter() {
+ Sema &S;
+ TemplateCandidateFilter(Sema &S) : S(S) {
WantTypeSpecifiers = false;
WantExpressionKeywords = false;
WantRemainingKeywords = false;
@@ -554,20 +625,22 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
};
bool ValidateCandidate(const TypoCorrection &Candidate) override {
if (auto *ND = Candidate.getCorrectionDecl())
- return isAcceptableTemplateName(ND->getASTContext(), ND, true);
+ return S.getAsTemplateNameDecl(ND);
return Candidate.isKeyword();
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<TemplateCandidateFilter>(*this);
+ }
};
DeclarationName Name = NameInfo.getName();
- if (TypoCorrection Corrected =
- CorrectTypo(NameInfo, LookupKind, S, &SS,
- llvm::make_unique<TemplateCandidateFilter>(),
- CTK_ErrorRecovery, LookupCtx)) {
+ TemplateCandidateFilter CCC(*this);
+ if (TypoCorrection Corrected = CorrectTypo(NameInfo, LookupKind, S, &SS, CCC,
+ CTK_ErrorRecovery, LookupCtx)) {
auto *ND = Corrected.getFoundDecl();
if (ND)
- ND = isAcceptableTemplateName(Context, ND,
- /*AllowFunctionTemplates*/ true);
+ ND = getAsTemplateNameDecl(ND);
if (ND || Corrected.isKeyword()) {
if (LookupCtx) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
@@ -1076,7 +1149,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// variable or variable template or the declaration of a function or
// function template.
- if (DS.isConstexprSpecified())
+ if (DS.hasConstexprSpecifier())
EmitDiag(DS.getConstexprSpecLoc());
// [dcl.fct.spec]p1:
@@ -1085,7 +1158,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (DS.isVirtualSpecified())
EmitDiag(DS.getVirtualSpecLoc());
- if (DS.isExplicitSpecified())
+ if (DS.hasExplicitSpecifier())
EmitDiag(DS.getExplicitSpecLoc());
if (DS.isNoreturnSpecified())
@@ -1110,6 +1183,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Invalid = true;
}
+ CheckFunctionOrTemplateParamDeclarator(S, D);
+
IdentifierInfo *ParamName = D.getIdentifier();
bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(
@@ -1765,8 +1840,8 @@ struct ConvertConstructorToDeductionGuideTransform {
return nullptr;
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
- return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo,
- CD->getBeginLoc(), CD->getLocation(),
+ return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(),
+ NewTInfo, CD->getBeginLoc(), CD->getLocation(),
CD->getEndLoc());
}
@@ -1795,8 +1870,8 @@ struct ConvertConstructorToDeductionGuideTransform {
Params.push_back(NewParam);
}
- return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
- Loc, Loc, Loc);
+ return buildDeductionGuide(Template->getTemplateParameters(),
+ ExplicitSpecifier(), TSI, Loc, Loc, Loc);
}
private:
@@ -1946,7 +2021,7 @@ private:
}
NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
- bool Explicit, TypeSourceInfo *TInfo,
+ ExplicitSpecifier ES, TypeSourceInfo *TInfo,
SourceLocation LocStart, SourceLocation Loc,
SourceLocation LocEnd) {
DeclarationNameInfo Name(DeductionGuideName, Loc);
@@ -1955,8 +2030,8 @@ private:
// Build the implicit deduction guide template.
auto *Guide =
- CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit,
- Name, TInfo->getType(), TInfo, LocEnd);
+ CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name,
+ TInfo->getType(), TInfo, LocEnd);
Guide->setImplicit();
Guide->setParams(Params);
@@ -1981,6 +2056,12 @@ private:
void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
SourceLocation Loc) {
+ if (CXXRecordDecl *DefRecord =
+ cast<CXXRecordDecl>(Template->getTemplatedDecl())->getDefinition()) {
+ TemplateDecl *DescribedTemplate = DefRecord->getDescribedClassTemplate();
+ Template = DescribedTemplate ? DescribedTemplate : Template;
+ }
+
DeclContext *DC = Template->getDeclContext();
if (DC->isDependentContext())
return;
@@ -3148,7 +3229,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template) ||
- isa<VarTemplateDecl>(Template)) {
+ isa<VarTemplateDecl>(Template) ||
+ isa<ConceptDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
@@ -3324,14 +3406,65 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
}
-TypeResult
-Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- TemplateTy TemplateD, IdentifierInfo *TemplateII,
- SourceLocation TemplateIILoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation RAngleLoc,
- bool IsCtorOrDtorName, bool IsClassName) {
+void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
+ TemplateNameKind &TNK,
+ SourceLocation NameLoc,
+ IdentifierInfo *&II) {
+ assert(TNK == TNK_Undeclared_template && "not an undeclared template name");
+
+ TemplateName Name = ParsedName.get();
+ auto *ATN = Name.getAsAssumedTemplateName();
+ assert(ATN && "not an assumed template name");
+ II = ATN->getDeclName().getAsIdentifierInfo();
+
+ if (!resolveAssumedTemplateNameAsType(S, Name, NameLoc, /*Diagnose*/false)) {
+ // Resolved to a type template name.
+ ParsedName = TemplateTy::make(Name);
+ TNK = TNK_Type_template;
+ }
+}
+
+bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name,
+ SourceLocation NameLoc,
+ bool Diagnose) {
+ // We assumed this undeclared identifier to be an (ADL-only) function
+ // template name, but it was used in a context where a type was required.
+ // Try to typo-correct it now.
+ AssumedTemplateStorage *ATN = Name.getAsAssumedTemplateName();
+ assert(ATN && "not an assumed template name");
+
+ LookupResult R(*this, ATN->getDeclName(), NameLoc, LookupOrdinaryName);
+ struct CandidateCallback : CorrectionCandidateCallback {
+ bool ValidateCandidate(const TypoCorrection &TC) override {
+ return TC.getCorrectionDecl() &&
+ getAsTypeTemplateDecl(TC.getCorrectionDecl());
+ }
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<CandidateCallback>(*this);
+ }
+ } FilterCCC;
+
+ TypoCorrection Corrected =
+ CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr,
+ FilterCCC, CTK_ErrorRecovery);
+ if (Corrected && Corrected.getFoundDecl()) {
+ diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest)
+ << ATN->getDeclName());
+ Name = TemplateName(Corrected.getCorrectionDeclAs<TemplateDecl>());
+ return false;
+ }
+
+ if (Diagnose)
+ Diag(R.getNameLoc(), diag::err_no_template) << R.getLookupName();
+ return true;
+}
+
+TypeResult Sema::ActOnTemplateIdType(
+ Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ TemplateTy TemplateD, IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc, SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc,
+ bool IsCtorOrDtorName, bool IsClassName) {
if (SS.isInvalid())
return true;
@@ -3372,6 +3505,9 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
}
TemplateName Template = TemplateD.get();
+ if (Template.getAsAssumedTemplateName() &&
+ resolveAssumedTemplateNameAsType(S, Template, TemplateIILoc))
+ return true;
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
@@ -3903,13 +4039,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization->setAccess(VarTemplate->getAccess());
}
- // Link instantiations of static data members back to the template from
- // which they were instantiated.
- if (Specialization->isStaticDataMember())
- Specialization->setInstantiationOfStaticDataMember(
- VarTemplate->getTemplatedDecl(),
- Specialization->getSpecializationKind());
-
return Specialization;
}
@@ -4108,6 +4237,18 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
}
}
+ExprResult
+Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ ConceptDecl *Template,
+ SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ // TODO: Do concept specialization here.
+ Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
+ "concept specialization";
+ return ExprError();
+}
+
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -4124,7 +4265,6 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
// vs template<class T, class U> void f(U);
// These should be filtered out by our callers.
- assert(!R.empty() && "empty lookup results when building templateid");
assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");
// Non-function templates require a template argument list.
@@ -4149,6 +4289,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
TemplateKWLoc, TemplateArgs);
}
+ if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
+ return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
+ R.getAsSingle<ConceptDecl>(),
+ TemplateKWLoc, TemplateArgs);
+ }
+
// We don't want lookup warnings at this point.
R.suppressDiagnostics();
@@ -4263,7 +4409,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
LookupOrdinaryName);
bool MOUS;
if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
- MOUS, TemplateKWLoc))
+ MOUS, TemplateKWLoc) && !R.isAmbiguous())
Diag(Name.getBeginLoc(), diag::err_no_member)
<< DNI.getName() << LookupCtx << SS.getRange();
return TNK_Non_template;
@@ -4763,10 +4909,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted);
- NTTPType = SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
- NTTP->getDeclName());
+
+ // If the parameter is a pack expansion, expand this slice of the pack.
+ if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
+ ArgumentPackIndex);
+ NTTPType = SubstType(PET->getPattern(),
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ } else {
+ NTTPType = SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ }
+
// If that worked, check the non-type template parameter type
// for validity.
if (!NTTPType.isNull())
@@ -6185,12 +6343,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
- Optional<unsigned> Depth;
- if (CTAK != CTAK_Specified)
- Depth = Param->getDepth() + 1;
+ Optional<unsigned> Depth = Param->getDepth() + 1;
+ Expr *DeductionArg = Arg;
+ if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg))
+ DeductionArg = PE->getPattern();
if (DeduceAutoType(
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
- Arg, ParamType, Depth) == DAR_Failed) {
+ DeductionArg, ParamType, Depth) == DAR_Failed) {
Diag(Arg->getExprLoc(),
diag::err_non_type_template_parm_type_deduction_failure)
<< Param->getDeclName() << Param->getType() << Arg->getType()
@@ -6242,9 +6401,24 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || Arg->isTypeDependent()) {
- // FIXME: Produce a cloned, canonical expression?
- Converted = TemplateArgument(Arg);
- return Arg;
+ // Force the argument to the type of the parameter to maintain invariants.
+ auto *PE = dyn_cast<PackExpansionExpr>(Arg);
+ if (PE)
+ Arg = PE->getPattern();
+ ExprResult E = ImpCastExprToType(
+ Arg, ParamType.getNonLValueExprType(Context), CK_Dependent,
+ ParamType->isLValueReferenceType() ? VK_LValue :
+ ParamType->isRValueReferenceType() ? VK_XValue : VK_RValue);
+ if (E.isInvalid())
+ return ExprError();
+ if (PE) {
+ // Recreate a pack expansion if we unwrapped one.
+ E = new (Context)
+ PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(),
+ PE->getNumExpansions());
+ }
+ Converted = TemplateArgument(E.get());
+ return E;
}
// The initialization of the parameter from the argument is
@@ -6273,10 +6447,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Convert the APValue to a TemplateArgument.
switch (Value.getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
assert(ParamType->isNullPtrType());
Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
break;
+ case APValue::Indeterminate:
+ llvm_unreachable("result of constant evaluation should be initialized");
+ break;
case APValue::Int:
assert(ParamType->isIntegralOrEnumerationType());
Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
@@ -6307,21 +6484,22 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a string literal
// -- the result of a typeid expression, or
// -- a predefined __func__ variable
- if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
- if (isa<CXXUuidofExpr>(E)) {
- Converted = TemplateArgument(ArgResult.get());
+ APValue::LValueBase Base = Value.getLValueBase();
+ auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
+ if (Base && !VD) {
+ auto *E = Base.dyn_cast<const Expr *>();
+ if (E && isa<CXXUuidofExpr>(E)) {
+ Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
break;
}
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
return ExprError();
}
- auto *VD = const_cast<ValueDecl *>(
- Value.getLValueBase().dyn_cast<const ValueDecl *>());
// -- a subobject
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
VD && VD->getType()->isArrayType() &&
- Value.getLValuePath()[0].ArrayIndex == 0 &&
+ Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
!Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
// Per defect report (no number yet):
// ... other than a pointer to the first element of a complete array
@@ -6342,6 +6520,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
case APValue::AddrLabelDiff:
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
+ case APValue::FixedPoint:
case APValue::Float:
case APValue::ComplexInt:
case APValue::ComplexFloat:
@@ -7816,7 +7995,74 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
return NewDecl;
}
-/// Strips various properties off an implicit instantiation
+Decl *Sema::ActOnConceptDefinition(Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ Expr *ConstraintExpr) {
+ DeclContext *DC = CurContext;
+
+ if (!DC->getRedeclContext()->isFileContext()) {
+ Diag(NameLoc,
+ diag::err_concept_decls_may_only_appear_in_global_namespace_scope);
+ return nullptr;
+ }
+
+ if (TemplateParameterLists.size() > 1) {
+ Diag(NameLoc, diag::err_concept_extra_headers);
+ return nullptr;
+ }
+
+ if (TemplateParameterLists.front()->size() == 0) {
+ Diag(NameLoc, diag::err_concept_no_parameters);
+ return nullptr;
+ }
+
+ ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
+ TemplateParameterLists.front(),
+ ConstraintExpr);
+
+ if (!ConstraintExpr->isTypeDependent() &&
+ ConstraintExpr->getType() != Context.BoolTy) {
+ // C++2a [temp.constr.atomic]p3:
+ // E shall be a constant expression of type bool.
+ // TODO: Do this check for individual atomic constraints
+ // and not the constraint expression. Probably should do it in
+ // ParseConstraintExpression.
+ Diag(ConstraintExpr->getSourceRange().getBegin(),
+ diag::err_concept_initialized_with_non_bool_type)
+ << ConstraintExpr->getType();
+ NewDecl->setInvalidDecl();
+ }
+
+ if (NewDecl->getAssociatedConstraints()) {
+ // C++2a [temp.concept]p4:
+ // A concept shall not have associated constraints.
+ // TODO: Make a test once we have actual associated constraints.
+ Diag(NameLoc, diag::err_concept_no_associated_constraints);
+ NewDecl->setInvalidDecl();
+ }
+
+ // Check for conflicting previous declaration.
+ DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ ForVisibleRedeclaration);
+ LookupName(Previous, S);
+
+ FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false,
+ /*AllowInlineNamespace*/false);
+ if (!Previous.empty()) {
+ auto *Old = Previous.getRepresentativeDecl();
+ Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition :
+ diag::err_redefinition_different_kind) << NewDecl->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ }
+
+ ActOnDocumentableDecl(NewDecl);
+ PushOnScopeChains(NewDecl, S);
+ return NewDecl;
+}
+
+/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
D->dropAttr<DLLImportAttr>();
@@ -8182,8 +8428,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
// here that have a different target.
if (LangOpts.CUDA &&
IdentifyCUDATarget(Specialization,
- /* IgnoreImplicitHDAttributes = */ true) !=
- IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttributes = */ true)) {
+ /* IgnoreImplicitHDAttr = */ true) !=
+ IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttr = */ true)) {
FailedCandidates.addCandidate().set(
I.getPair(), FunTmpl->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info));
@@ -8243,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// FIXME: We need an update record for this AST mutation.
// FIXME: What if there are multiple such prior declarations (for instance,
// from different modules)?
- Specialization->setConstexpr(FD->isConstexpr());
+ Specialization->setConstexprKind(FD->getConstexprKind());
}
// FIXME: Check if the prior specialization has a point of instantiation.
@@ -8594,6 +8840,29 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
return false;
}
+/// Common checks for whether an explicit instantiation of \p D is valid.
+static bool CheckExplicitInstantiation(Sema &S, NamedDecl *D,
+ SourceLocation InstLoc,
+ bool WasQualifiedName,
+ TemplateSpecializationKind TSK) {
+ // C++ [temp.explicit]p13:
+ // An explicit instantiation declaration shall not name a specialization of
+ // a template with internal linkage.
+ if (TSK == TSK_ExplicitInstantiationDeclaration &&
+ D->getFormalLinkage() == InternalLinkage) {
+ S.Diag(InstLoc, diag::err_explicit_instantiation_internal_linkage) << D;
+ return true;
+ }
+
+ // C++11 [temp.explicit]p3: [DR 275]
+ // An explicit instantiation shall appear in an enclosing namespace of its
+ // template.
+ if (CheckExplicitInstantiationScope(S, D, InstLoc, WasQualifiedName))
+ return true;
+
+ return false;
+}
+
/// Determine whether the given scope specifier has a template-id in it.
static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
if (!SS.isSet())
@@ -8684,8 +8953,10 @@ DeclResult Sema::ActOnExplicitInstantiation(
? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
- if (TSK == TSK_ExplicitInstantiationDeclaration) {
- // Check for dllexport class template instantiation declarations.
+ if (TSK == TSK_ExplicitInstantiationDeclaration &&
+ !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
+ // Check for dllexport class template instantiation declarations,
+ // except for MinGW mode.
for (const ParsedAttr &AL : Attr) {
if (AL.getKind() == ParsedAttr::AT_DLLExport) {
Diag(ExternLoc,
@@ -8745,13 +9016,21 @@ DeclResult Sema::ActOnExplicitInstantiation(
TemplateSpecializationKind PrevDecl_TSK
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
- // C++0x [temp.explicit]p2:
- // [...] An explicit instantiation shall appear in an enclosing
- // namespace of its template. [...]
- //
- // This is C++ DR 275.
- if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc,
- SS.isSet()))
+ if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl != nullptr &&
+ Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
+ // Check for dllexport class template instantiation definitions in MinGW
+ // mode, if a previous declaration of the instantiation was seen.
+ for (const ParsedAttr &AL : Attr) {
+ if (AL.getKind() == ParsedAttr::AT_DLLExport) {
+ Diag(AL.getLoc(),
+ diag::warn_attribute_dllexport_explicit_instantiation_def);
+ break;
+ }
+ }
+ }
+
+ if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
+ SS.isSet(), TSK))
return true;
ClassTemplateSpecializationDecl *Specialization = nullptr;
@@ -8906,6 +9185,14 @@ DeclResult Sema::ActOnExplicitInstantiation(
dllExportImportClassTemplateSpecialization(*this, Def);
}
+ // In MinGW mode, export the template instantiation if the declaration
+ // was marked dllexport.
+ if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration &&
+ Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() &&
+ PrevDecl->hasAttr<DLLExportAttr>()) {
+ dllExportImportClassTemplateSpecialization(*this, Def);
+ }
+
// Set the template specialization kind. Make sure it is set before
// instantiating the members which will trigger ASTConsumer callbacks.
Specialization->setTemplateSpecializationKind(TSK);
@@ -8974,12 +9261,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc,
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
- // C++0x [temp.explicit]p2:
- // [...] An explicit instantiation shall appear in an enclosing
- // namespace of its template. [...]
- //
- // This is C++ DR 275.
- CheckExplicitInstantiationScope(*this, Record, NameLoc, true);
+ CheckExplicitInstantiation(*this, Record, NameLoc, true, TSK);
// Verify that it is okay to explicitly instantiate here.
CXXRecordDecl *PrevDecl
@@ -9096,7 +9378,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::err_explicit_instantiation_inline :
diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
- if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType())
+ if (D.getDeclSpec().hasConstexprSpecifier() && R->isFunctionType())
// FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is
// not already specified.
Diag(D.getDeclSpec().getConstexprSpecLoc(),
@@ -9137,7 +9419,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!PrevTemplate) {
if (!Prev || !Prev->isStaticDataMember()) {
- // We expect to see a data data member here.
+ // We expect to see a static data member here.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
<< Name;
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
@@ -9210,8 +9492,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::ext_explicit_instantiation_without_qualified_id)
<< Prev << D.getCXXScopeSpec().getRange();
- // Check the scope of this explicit instantiation.
- CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
+ CheckExplicitInstantiation(*this, Prev, D.getIdentifierLoc(), true, TSK);
// Verify that it is okay to explicitly instantiate here.
TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
@@ -9306,7 +9587,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// have a different target.
if (LangOpts.CUDA &&
IdentifyCUDATarget(Specialization,
- /* IgnoreImplicitHDAttributes = */ true) !=
+ /* IgnoreImplicitHDAttr = */ true) !=
IdentifyCUDATarget(D.getDeclSpec().getAttributes())) {
FailedCandidates.addCandidate().set(
P.getPair(), FunTmpl->getTemplatedDecl(),
@@ -9386,6 +9667,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return (Decl*) nullptr;
}
+ // HACK: libc++ has a bug where it attempts to explicitly instantiate the
+ // functions
+ // valarray<size_t>::valarray(size_t) and
+ // valarray<size_t>::~valarray()
+ // that it declared to have internal linkage with the internal_linkage
+ // attribute. Ignore the explicit instantiation declaration in this case.
+ if (Specialization->hasAttr<InternalLinkageAttr>() &&
+ TSK == TSK_ExplicitInstantiationDeclaration) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getDeclContext()))
+ if (RD->getIdentifier() && RD->getIdentifier()->isStr("valarray") &&
+ RD->isInStdNamespace())
+ return (Decl*) nullptr;
+ }
+
ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes());
// In MSVC mode, dllimported explicit instantiation definitions are treated as
@@ -9419,11 +9714,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::ext_explicit_instantiation_without_qualified_id)
<< Specialization << D.getCXXScopeSpec().getRange();
- CheckExplicitInstantiationScope(*this,
- FunTmpl? (NamedDecl *)FunTmpl
- : Specialization->getInstantiatedFromMemberFunction(),
- D.getIdentifierLoc(),
- D.getCXXScopeSpec().isSet());
+ CheckExplicitInstantiation(
+ *this,
+ FunTmpl ? (NamedDecl *)FunTmpl
+ : Specialization->getInstantiatedFromMemberFunction(),
+ D.getIdentifierLoc(), D.getCXXScopeSpec().isSet(), TSK);
// FIXME: Create some kind of ExplicitInstantiationDecl here.
return (Decl*) nullptr;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index f2f989ce1241..b55a232d26c2 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1,9 +1,8 @@
//===- SemaTemplateDeduction.cpp - Template Argument Deduction ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -1671,8 +1670,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
const FunctionProtoType *FunctionProtoParam =
cast<FunctionProtoType>(Param);
- if (FunctionProtoParam->getTypeQuals()
- != FunctionProtoArg->getTypeQuals() ||
+ if (FunctionProtoParam->getMethodQuals()
+ != FunctionProtoArg->getMethodQuals() ||
FunctionProtoParam->getRefQualifier()
!= FunctionProtoArg->getRefQualifier() ||
FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
@@ -2873,7 +2872,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
return Sema::TDK_SubstitutionFailure;
return ::FinishTemplateArgumentDeduction(
- *this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info);
+ *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info);
}
/// Perform template argument deduction to determine whether
@@ -2914,7 +2913,7 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
return Sema::TDK_SubstitutionFailure;
return ::FinishTemplateArgumentDeduction(
- *this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info);
+ *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info);
}
/// Determine whether the given type T is a simple-template-id type.
@@ -3082,7 +3081,7 @@ Sema::SubstituteExplicitTemplateArguments(
CXXRecordDecl *ThisContext = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
ThisContext = Method->getParent();
- ThisTypeQuals = Method->getTypeQualifiers();
+ ThisTypeQuals = Method->getMethodQualifiers();
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals,
@@ -4281,19 +4280,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
namespace {
+ struct DependentAuto { bool IsPack; };
/// Substitute the 'auto' specifier or deduced template specialization type
/// specifier within a type for a given replacement type.
class SubstituteDeducedTypeTransform :
public TreeTransform<SubstituteDeducedTypeTransform> {
QualType Replacement;
+ bool ReplacementIsPack;
bool UseTypeSugar;
public:
+ SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA)
+ : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), Replacement(),
+ ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {}
+
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
- bool UseTypeSugar = true)
+ bool UseTypeSugar = true)
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
- Replacement(Replacement), UseTypeSugar(UseTypeSugar) {}
+ Replacement(Replacement), ReplacementIsPack(false),
+ UseTypeSugar(UseTypeSugar) {}
QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
assert(isa<TemplateTypeParmType>(Replacement) &&
@@ -4318,7 +4324,8 @@ namespace {
return TransformDesugared(TLB, TL);
QualType Result = SemaRef.Context.getAutoType(
- Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
+ Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
+ ReplacementIsPack);
auto NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -4409,9 +4416,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
Init = NonPlaceholder.get();
}
+ DependentAuto DependentResult = {
+ /*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
+
if (!DependentDeductionDepth &&
(Type.getType()->isDependentType() || Init->isTypeDependent())) {
- Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
+ Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
@@ -4479,7 +4489,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
auto DeductionFailed = [&](TemplateDeductionResult TDK,
ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
if (Init->isTypeDependent()) {
- Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
+ Result =
+ SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
@@ -4560,7 +4571,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
QualType Sema::SubstAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
if (TypeToReplaceAuto->isDependentType())
- TypeToReplaceAuto = QualType();
+ return SubstituteDeducedTypeTransform(
+ *this, DependentAuto{
+ TypeToReplaceAuto->containsUnexpandedParameterPack()})
+ .TransformType(TypeWithAuto);
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
@@ -4568,7 +4582,11 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto,
TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType TypeToReplaceAuto) {
if (TypeToReplaceAuto->isDependentType())
- TypeToReplaceAuto = QualType();
+ return SubstituteDeducedTypeTransform(
+ *this,
+ DependentAuto{
+ TypeToReplaceAuto->containsUnexpandedParameterPack()})
+ .TransformType(TypeWithAuto);
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
@@ -4661,7 +4679,7 @@ AddImplicitObjectParameterType(ASTContext &Context,
// The standard doesn't say explicitly, but we pick the appropriate kind of
// reference type based on [over.match.funcs]p4.
QualType ArgTy = Context.getTypeDeclType(Method->getParent());
- ArgTy = Context.getQualifiedType(ArgTy, Method->getTypeQualifiers());
+ ArgTy = Context.getQualifiedType(ArgTy, Method->getMethodQualifiers());
if (Method->getRefQualifier() == RQ_RValue)
ArgTy = Context.getRValueReferenceType(ArgTy);
else
@@ -5049,7 +5067,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
Info);
auto *TST1 = T1->castAs<TemplateSpecializationType>();
if (FinishTemplateArgumentDeduction(
- S, P2, /*PartialOrdering=*/true,
+ S, P2, /*IsPartialOrdering=*/true,
TemplateArgumentList(TemplateArgumentList::OnStack,
TST1->template_arguments()),
Deduced, Info))
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 96abeed82493..973f564d3058 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1,9 +1,8 @@
//===------- SemaTemplateInstantiate.cpp - C++ Template Instantiation ------===/
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===/
//
// This file implements C++ template instantiation.
@@ -26,6 +25,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace clang;
using namespace sema;
@@ -66,9 +66,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
if (!Ctx) {
Ctx = D->getDeclContext();
- // Add template arguments from a variable template instantiation.
- if (VarTemplateSpecializationDecl *Spec =
- dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ // Add template arguments from a variable template instantiation. For a
+ // class-scope explicit specialization, there are no template arguments
+ // at this level, but there may be enclosing template arguments.
+ VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(D);
+ if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
// We're done when we hit an explicit specialization.
if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
!isa<VarTemplatePartialSpecializationDecl>(Spec))
@@ -111,8 +114,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
while (!Ctx->isFileContext()) {
// Add template arguments from a class template instantiation.
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+ ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
+ if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
// We're done when we hit an explicit specialization.
if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
!isa<ClassTemplatePartialSpecializationDecl>(Spec))
@@ -129,9 +133,8 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// Add template arguments from a function template specialization.
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
if (!RelativeToPrimary &&
- (Function->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization &&
- !Function->getClassScopeSpecializationPattern()))
+ Function->getTemplateSpecializationKindForInstantiation() ==
+ TSK_ExplicitSpecialization)
break;
if (const TemplateArgumentList *TemplateArgs
@@ -816,7 +819,19 @@ namespace {
SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
}
- void transformedLocalDecl(Decl *Old, Decl *New) {
+ void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) {
+ if (Old->isParameterPack()) {
+ SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old);
+ for (auto *New : NewDecls)
+ SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(
+ Old, cast<VarDecl>(New));
+ return;
+ }
+
+ assert(NewDecls.size() == 1 &&
+ "should only have multiple expansions for a pack");
+ Decl *New = NewDecls.front();
+
// If we've instantiated the call operator of a lambda or the call
// operator template of a generic lambda, update the "instantiation of"
// information.
@@ -885,12 +900,11 @@ namespace {
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E);
- /// Rebuild a DeclRefExpr for a ParmVarDecl reference.
- ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc);
+ /// Rebuild a DeclRefExpr for a VarDecl reference.
+ ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc);
- /// Transform a reference to a function parameter pack.
- ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E,
- ParmVarDecl *PD);
+ /// Transform a reference to a function or init-capture parameter pack.
+ ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, VarDecl *PD);
/// Transform a FunctionParmPackExpr which was built when we couldn't
/// expand a function parameter pack reference which refers to an expanded
@@ -1321,9 +1335,8 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
Arg);
}
-ExprResult
-TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD,
- SourceLocation Loc) {
+ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
+ SourceLocation Loc) {
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD);
}
@@ -1332,11 +1345,11 @@ ExprResult
TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
if (getSema().ArgumentPackSubstitutionIndex != -1) {
// We can expand this parameter pack now.
- ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex);
- ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D));
+ VarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex);
+ VarDecl *VD = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), D));
if (!VD)
return ExprError();
- return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc());
+ return RebuildVarDeclRefExpr(VD, E->getExprLoc());
}
QualType T = TransformType(E->getType());
@@ -1345,25 +1358,26 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
// Transform each of the parameter expansions into the corresponding
// parameters in the instantiation of the function decl.
- SmallVector<ParmVarDecl *, 8> Parms;
- Parms.reserve(E->getNumExpansions());
+ SmallVector<VarDecl *, 8> Vars;
+ Vars.reserve(E->getNumExpansions());
for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
I != End; ++I) {
- ParmVarDecl *D =
- cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I));
+ VarDecl *D = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), *I));
if (!D)
return ExprError();
- Parms.push_back(D);
+ Vars.push_back(D);
}
- return FunctionParmPackExpr::Create(getSema().Context, T,
- E->getParameterPack(),
- E->getParameterPackLocation(), Parms);
+ auto *PackExpr =
+ FunctionParmPackExpr::Create(getSema().Context, T, E->getParameterPack(),
+ E->getParameterPackLocation(), Vars);
+ getSema().MarkFunctionParmPackReferenced(PackExpr);
+ return PackExpr;
}
ExprResult
TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
- ParmVarDecl *PD) {
+ VarDecl *PD) {
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
= getSema().CurrentInstantiationScope->findInstantiationOf(PD);
@@ -1377,8 +1391,10 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
QualType T = TransformType(E->getType());
if (T.isNull())
return ExprError();
- return FunctionParmPackExpr::Create(getSema().Context, T, PD,
- E->getExprLoc(), *Pack);
+ auto *PackExpr = FunctionParmPackExpr::Create(getSema().Context, T, PD,
+ E->getExprLoc(), *Pack);
+ getSema().MarkFunctionParmPackReferenced(PackExpr);
+ return PackExpr;
}
TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex];
@@ -1387,8 +1403,7 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
}
// We have either an unexpanded pack or a specific expansion.
- return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl),
- E->getExprLoc());
+ return RebuildVarDeclRefExpr(cast<VarDecl>(TransformedDecl), E->getExprLoc());
}
ExprResult
@@ -1406,7 +1421,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
}
// Handle references to function parameter packs.
- if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D))
+ if (VarDecl *PD = dyn_cast<VarDecl>(D))
if (PD->isParameterPack())
return TransformFunctionParmPackRefExpr(E, PD);
@@ -2009,6 +2024,15 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Instantiation->getInstantiatedFromMemberClass(),
Pattern, PatternDef, TSK, Complain))
return true;
+
+ llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
Pattern = PatternDef;
// Record the point of instantiation.
@@ -2070,6 +2094,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
LateInstantiatedAttrVec LateAttrs;
Instantiator.enableLateAttributeInstantiation(&LateAttrs);
+ bool MightHaveConstexprVirtualFunctions = false;
for (auto *Member : Pattern->decls()) {
// Don't instantiate members not belonging in this semantic context.
// e.g. for:
@@ -2116,6 +2141,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Instantiation->setInvalidDecl();
break;
}
+ } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewMember)) {
+ if (MD->isConstexpr() && !MD->getFriendObjectKind() &&
+ (MD->isVirtualAsWritten() || Instantiation->getNumBases()))
+ MightHaveConstexprVirtualFunctions = true;
}
if (NewMember->isInvalidDecl())
@@ -2208,9 +2237,14 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Consumer.HandleTagDeclDefinition(Instantiation);
// Always emit the vtable for an explicit instantiation definition
- // of a polymorphic class template specialization.
+ // of a polymorphic class template specialization. Otherwise, eagerly
+ // instantiate only constexpr virtual functions in preparation for their use
+ // in constant evaluation.
if (TSK == TSK_ExplicitInstantiationDefinition)
MarkVTableUsed(PointOfInstantiation, Instantiation, true);
+ else if (MightHaveConstexprVirtualFunctions)
+ MarkVirtualMembersReferenced(PointOfInstantiation, Instantiation,
+ /*ConstexprOnly*/ true);
}
return Instantiation->isInvalidDecl();
@@ -2675,11 +2709,14 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
== TSK_ExplicitSpecialization)
continue;
- if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
+ if (Context.getTargetInfo().getTriple().isOSWindows() &&
TSK == TSK_ExplicitInstantiationDeclaration) {
- // In MSVC and Windows Itanium mode, explicit instantiation decl of the
- // outer class doesn't affect the inner class.
+ // On Windows, explicit instantiation decl of the outer class doesn't
+ // affect the inner class. Typically extern template declarations are
+ // used in combination with dll import/export annotations, but those
+ // are not propagated from the outer class templates to inner classes.
+ // Therefore, do not instantiate inner classes on this platform, so
+ // that users don't end up with undefined symbols during linking.
continue;
}
@@ -2887,7 +2924,7 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) {
unsigned i = PV->getFunctionScopeIndex();
// This parameter might be from a freestanding function type within the
// function and isn't necessarily referring to one of FD's parameters.
- if (FD->getParamDecl(i) == PV)
+ if (i < FD->getNumParams() && FD->getParamDecl(i) == PV)
return FD->getCanonicalDecl()->getParamDecl(i);
}
}
@@ -2959,14 +2996,14 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
#endif
Stored = Inst;
} else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) {
- Pack->push_back(cast<ParmVarDecl>(Inst));
+ Pack->push_back(cast<VarDecl>(Inst));
} else {
assert(Stored.get<Decl *>() == Inst && "Already instantiated this local");
}
}
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
- ParmVarDecl *Inst) {
+ VarDecl *Inst) {
D = getCanonicalParmVarDecl(D);
DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
Pack->push_back(Inst);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index fad3c065e896..67343d11d333 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1,9 +1,8 @@
//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===/
//
// This file implements C++ template instantiation for declarations.
@@ -24,6 +23,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/TimeProfiler.h"
using namespace clang;
@@ -285,7 +285,7 @@ static void instantiateOMPDeclareSimdDeclAttr(
SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps;
SmallVector<unsigned, 4> LinModifiers;
- auto &&Subst = [&](Expr *E) -> ExprResult {
+ auto SubstExpr = [&](Expr *E) -> ExprResult {
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
Sema::ContextRAII SavedContext(S, FD);
@@ -300,6 +300,17 @@ static void instantiateOMPDeclareSimdDeclAttr(
return S.SubstExpr(E, TemplateArgs);
};
+ // Substitute a single OpenMP clause, which is a potentially-evaluated
+ // full-expression.
+ auto Subst = [&](Expr *E) -> ExprResult {
+ EnterExpressionEvaluationContext Evaluated(
+ S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ ExprResult Res = SubstExpr(E);
+ if (Res.isInvalid())
+ return Res;
+ return S.ActOnFinishFullExpr(Res.get(), false);
+ };
+
ExprResult Simdlen;
if (auto *E = Attr.getSimdlen())
Simdlen = Subst(E);
@@ -345,6 +356,74 @@ static void instantiateOMPDeclareSimdDeclAttr(
Attr.getRange());
}
+static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) {
+ // Both min and max expression are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ Expr *MinExpr = Result.getAs<Expr>();
+
+ Result = S.SubstExpr(Attr.getMax(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ Expr *MaxExpr = Result.getAs<Expr>();
+
+ S.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
+ Attr.getSpellingListIndex());
+}
+
+static ExplicitSpecifier
+instantiateExplicitSpecifier(Sema &S,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ ExplicitSpecifier ES, FunctionDecl *New) {
+ if (!ES.getExpr())
+ return ES;
+ Expr *OldCond = ES.getExpr();
+ Expr *Cond = nullptr;
+ {
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs);
+ if (SubstResult.isInvalid()) {
+ return ExplicitSpecifier::Invalid();
+ }
+ Cond = SubstResult.get();
+ }
+ ExplicitSpecifier Result(Cond, ES.getKind());
+ if (!Cond->isTypeDependent())
+ S.tryResolveExplicitSpecifier(Result);
+ return Result;
+}
+
+static void instantiateDependentAMDGPUWavesPerEUAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
+ // Both min and max expression are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ Expr *MinExpr = Result.getAs<Expr>();
+
+ Expr *MaxExpr = nullptr;
+ if (auto Max = Attr.getMax()) {
+ Result = S.SubstExpr(Max, TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ MaxExpr = Result.getAs<Expr>();
+ }
+
+ S.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
+ Attr.getSpellingListIndex());
+}
+
void Sema::InstantiateAttrsForDecl(
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
Decl *New, LateInstantiatedAttrVec *LateAttrs,
@@ -438,6 +517,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize =
+ dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) {
+ instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
+ *this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New);
+ }
+
+ if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize =
+ dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) {
+ instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs,
+ *AMDGPUFlatWorkGroupSize, New);
+ }
+
// Existing DLL attribute on the instantiation takes precedence.
if (TmplAttr->getKind() == attr::DLLExport ||
TmplAttr->getKind() == attr::DLLImport) {
@@ -1633,6 +1724,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
+ ExplicitSpecifier InstantiatedExplicitSpecifier;
+ if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
+ InstantiatedExplicitSpecifier = instantiateExplicitSpecifier(
+ SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide);
+ if (InstantiatedExplicitSpecifier.isInvalid())
+ return nullptr;
+ }
+
SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
@@ -1670,8 +1769,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
Function = CXXDeductionGuideDecl::Create(
- SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
- NameInfo, T, TInfo, D->getSourceRange().getEnd());
+ SemaRef.Context, DC, D->getInnerLocStart(),
+ InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
+ D->getSourceRange().getEnd());
if (DGuide->isCopyDeductionCandidate())
cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
Function->setAccess(D->getAccess());
@@ -1679,7 +1779,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->isConstexpr());
+ D->hasWrittenPrototype(), D->getConstexprKind());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
@@ -1894,10 +1994,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return Function;
}
-Decl *
-TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
- TemplateParameterList *TemplateParams,
- bool IsClassScopeSpecialization) {
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
+ CXXMethodDecl *D, TemplateParameterList *TemplateParams,
+ Optional<const ASTTemplateArgumentListInfo *>
+ ClassScopeSpecializationArgs) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
@@ -1939,6 +2039,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
}
}
+ ExplicitSpecifier InstantiatedExplicitSpecifier =
+ instantiateExplicitSpecifier(SemaRef, TemplateArgs,
+ ExplicitSpecifier::getFromDecl(D), D);
+ if (InstantiatedExplicitSpecifier.isInvalid())
+ return nullptr;
+
SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
@@ -1978,11 +2084,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
- StartLoc, NameInfo, T, TInfo,
- Constructor->isExplicit(),
- Constructor->isInlineSpecified(),
- false, Constructor->isConstexpr());
+ Method = CXXConstructorDecl::Create(
+ SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
+ InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
+ Constructor->getConstexprKind());
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
@@ -1993,13 +2098,13 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
- Conversion->isInlineSpecified(), Conversion->isExplicit(),
- Conversion->isConstexpr(), Conversion->getEndLoc());
+ Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
+ Conversion->getConstexprKind(), Conversion->getEndLoc());
} else {
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo,
T, TInfo, SC, D->isInlineSpecified(),
- D->isConstexpr(), D->getEndLoc());
+ D->getConstexprKind(), D->getEndLoc());
}
if (D->isInlined())
@@ -2101,7 +2206,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *Info =
- D->getTemplateSpecializationArgsAsWritten()) {
+ ClassScopeSpecializationArgs.getValueOr(
+ D->getTemplateSpecializationArgsAsWritten())) {
SemaRef.LookupQualifiedName(Previous, DC);
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
@@ -2116,6 +2222,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setInvalidDecl();
IsExplicitSpecialization = true;
+ } else if (ClassScopeSpecializationArgs) {
+ // Class-scope explicit specialization written without explicit template
+ // arguments.
+ SemaRef.LookupQualifiedName(Previous, DC);
+ if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous))
+ Method->setInvalidDecl();
+
+ IsExplicitSpecialization = true;
} else if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
@@ -2127,9 +2241,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Previous.clear();
}
- if (!IsClassScopeSpecialization)
- SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
- IsExplicitSpecialization);
+ SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
+ IsExplicitSpecialization);
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
@@ -2152,6 +2265,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isDeletedAsWritten())
SemaRef.SetDeclDeleted(Method, Method->getLocation());
+ // If this is an explicit specialization, mark the implicitly-instantiated
+ // template specialization as being an explicit specialization too.
+ // FIXME: Is this necessary?
+ if (IsExplicitSpecialization && !isFriend)
+ SemaRef.CompleteMemberSpecialization(Method, Previous);
+
// If there's a function template, let our caller handle it.
if (FunctionTemplate) {
// do nothing
@@ -2172,10 +2291,24 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// Otherwise, add the declaration. We don't need to do this for
// class-scope specializations because we'll have matched them with
// the appropriate template.
- } else if (!IsClassScopeSpecialization) {
+ } else {
Owner->addDecl(Method);
}
+ // PR17480: Honor the used attribute to instantiate member function
+ // definitions
+ if (Method->hasAttr<UsedAttr>()) {
+ if (const auto *A = dyn_cast<CXXRecordDecl>(Owner)) {
+ SourceLocation Loc;
+ if (const MemberSpecializationInfo *MSInfo =
+ A->getMemberSpecializationInfo())
+ Loc = MSInfo->getPointOfInstantiation();
+ else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(A))
+ Loc = Spec->getPointOfInstantiation();
+ SemaRef.MarkFunctionReferenced(Loc, Method);
+ }
+ }
+
return Method;
}
@@ -2768,38 +2901,8 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) {
Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) {
CXXMethodDecl *OldFD = Decl->getSpecialization();
- CXXMethodDecl *NewFD =
- cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true));
- if (!NewFD)
- return nullptr;
-
- TemplateArgumentListInfo ExplicitTemplateArgs;
- TemplateArgumentListInfo *ExplicitTemplateArgsPtr = nullptr;
- if (Decl->hasExplicitTemplateArgs()) {
- if (SemaRef.Subst(Decl->templateArgs().getArgumentArray(),
- Decl->templateArgs().size(), ExplicitTemplateArgs,
- TemplateArgs))
- return nullptr;
- ExplicitTemplateArgsPtr = &ExplicitTemplateArgs;
- }
-
- LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
- Sema::ForExternalRedeclaration);
- SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext);
- if (SemaRef.CheckFunctionTemplateSpecialization(
- NewFD, ExplicitTemplateArgsPtr, Previous)) {
- NewFD->setInvalidDecl();
- return NewFD;
- }
-
- // Associate the specialization with the pattern.
- FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl());
- assert(Specialization && "Class scope Specialization is null");
- SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD);
-
- // FIXME: If this is a definition, check for redefinition errors!
-
- return NewFD;
+ return cast_or_null<CXXMethodDecl>(
+ VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten()));
}
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
@@ -2820,6 +2923,32 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
return TD;
}
+Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
+ SmallVector<Expr *, 5> Vars;
+ for (auto *I : D->varlists()) {
+ Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get();
+ assert(isa<DeclRefExpr>(Var) && "allocate arg is not a DeclRefExpr");
+ Vars.push_back(Var);
+ }
+ SmallVector<OMPClause *, 4> Clauses;
+ // Copy map clauses from the original mapper.
+ for (OMPClause *C : D->clauselists()) {
+ auto *AC = cast<OMPAllocatorClause>(C);
+ ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs);
+ if (!NewE.isUsable())
+ continue;
+ OMPClause *IC = SemaRef.ActOnOpenMPAllocatorClause(
+ NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc());
+ Clauses.push_back(IC);
+ }
+
+ Sema::DeclGroupPtrTy Res = SemaRef.ActOnOpenMPAllocateDirective(
+ D->getLocation(), Vars, Clauses, Owner);
+ if (Res.get().isNull())
+ return nullptr;
+ return Res.get().getSingleDecl();
+}
+
Decl *TemplateDeclInstantiator::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
llvm_unreachable(
"Requires directive cannot be instantiated within a dependent context");
@@ -2925,6 +3054,95 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
return NewDRD;
}
+Decl *
+TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
+ // Instantiate type and check if it is allowed.
+ const bool RequiresInstantiation =
+ D->getType()->isDependentType() ||
+ D->getType()->isInstantiationDependentType() ||
+ D->getType()->containsUnexpandedParameterPack();
+ QualType SubstMapperTy;
+ DeclarationName VN = D->getVarName();
+ if (RequiresInstantiation) {
+ SubstMapperTy = SemaRef.ActOnOpenMPDeclareMapperType(
+ D->getLocation(),
+ ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs,
+ D->getLocation(), VN)));
+ } else {
+ SubstMapperTy = D->getType();
+ }
+ if (SubstMapperTy.isNull())
+ return nullptr;
+ // Create an instantiated copy of mapper.
+ auto *PrevDeclInScope = D->getPrevDeclInScope();
+ if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) {
+ PrevDeclInScope = cast<OMPDeclareMapperDecl>(
+ SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope)
+ ->get<Decl *>());
+ }
+ OMPDeclareMapperDecl *NewDMD = SemaRef.ActOnOpenMPDeclareMapperDirectiveStart(
+ /*S=*/nullptr, Owner, D->getDeclName(), SubstMapperTy, D->getLocation(),
+ VN, D->getAccess(), PrevDeclInScope);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDMD);
+ SmallVector<OMPClause *, 6> Clauses;
+ bool IsCorrect = true;
+ if (!RequiresInstantiation) {
+ // Copy the mapper variable.
+ NewDMD->setMapperVarRef(D->getMapperVarRef());
+ // Copy map clauses from the original mapper.
+ for (OMPClause *C : D->clauselists())
+ Clauses.push_back(C);
+ } else {
+ // Instantiate the mapper variable.
+ DeclarationNameInfo DirName;
+ SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr,
+ (*D->clauselist_begin())->getBeginLoc());
+ SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl(
+ NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ cast<DeclRefExpr>(D->getMapperVarRef())->getDecl(),
+ cast<DeclRefExpr>(NewDMD->getMapperVarRef())->getDecl());
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
+ Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(),
+ ThisContext);
+ // Instantiate map clauses.
+ for (OMPClause *C : D->clauselists()) {
+ auto *OldC = cast<OMPMapClause>(C);
+ SmallVector<Expr *, 4> NewVars;
+ for (Expr *OE : OldC->varlists()) {
+ Expr *NE = SemaRef.SubstExpr(OE, TemplateArgs).get();
+ if (!NE) {
+ IsCorrect = false;
+ break;
+ }
+ NewVars.push_back(NE);
+ }
+ if (!IsCorrect)
+ break;
+ NestedNameSpecifierLoc NewQualifierLoc =
+ SemaRef.SubstNestedNameSpecifierLoc(OldC->getMapperQualifierLoc(),
+ TemplateArgs);
+ CXXScopeSpec SS;
+ SS.Adopt(NewQualifierLoc);
+ DeclarationNameInfo NewNameInfo = SemaRef.SubstDeclarationNameInfo(
+ OldC->getMapperIdInfo(), TemplateArgs);
+ OMPVarListLocTy Locs(OldC->getBeginLoc(), OldC->getLParenLoc(),
+ OldC->getEndLoc());
+ OMPClause *NewC = SemaRef.ActOnOpenMPMapClause(
+ OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(), SS,
+ NewNameInfo, OldC->getMapType(), OldC->isImplicitMapType(),
+ OldC->getMapLoc(), OldC->getColonLoc(), NewVars, Locs);
+ Clauses.push_back(NewC);
+ }
+ SemaRef.EndOpenMPDSABlock(nullptr);
+ }
+ (void)SemaRef.ActOnOpenMPDeclareMapperDirectiveEnd(NewDMD, /*S=*/nullptr,
+ Clauses);
+ if (!IsCorrect)
+ return nullptr;
+ return NewDMD;
+}
+
Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl(
OMPCapturedExprDecl * /*D*/) {
llvm_unreachable("Should not be met in templates");
@@ -2962,13 +3180,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
"for a member class template");
// Lookup the already-instantiated declaration in the instantiation
- // of the class template. FIXME: Diagnose or assert if this fails?
- DeclContext::lookup_result Found
- = Owner->lookup(ClassTemplate->getDeclName());
- if (Found.empty())
- return nullptr;
- ClassTemplateDecl *InstClassTemplate
- = dyn_cast<ClassTemplateDecl>(Found.front());
+ // of the class template.
+ ClassTemplateDecl *InstClassTemplate =
+ cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl(
+ D->getLocation(), ClassTemplate, TemplateArgs));
if (!InstClassTemplate)
return nullptr;
@@ -3077,6 +3292,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Instantiate the members of the class-scope explicit specialization eagerly.
// We don't have support for lazy instantiation of an explicit specialization
// yet, and MSVC eagerly instantiates in this case.
+ // FIXME: This is wrong in standard C++.
if (D->isThisDeclarationADefinition() &&
SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
TSK_ImplicitInstantiation,
@@ -3094,6 +3310,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
assert(VarTemplate &&
"A template specialization without specialized template?");
+ VarTemplateDecl *InstVarTemplate =
+ cast_or_null<VarTemplateDecl>(SemaRef.FindInstantiatedDecl(
+ D->getLocation(), VarTemplate, TemplateArgs));
+ if (!InstVarTemplate)
+ return nullptr;
+
// Substitute the current template arguments.
const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo();
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc());
@@ -3105,28 +3327,33 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(
- VarTemplate, VarTemplate->getBeginLoc(),
- const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
- Converted))
+ if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
+ VarTemplateArgsInfo, false, Converted))
return nullptr;
- // Find the variable template specialization declaration that
- // corresponds to these arguments.
+ // Check whether we've already seen a declaration of this specialization.
void *InsertPos = nullptr;
- if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization(
- Converted, InsertPos))
- // If we already have a variable template specialization, return it.
- return VarSpec;
+ VarTemplateSpecializationDecl *PrevDecl =
+ InstVarTemplate->findSpecialization(Converted, InsertPos);
+
+ // Check whether we've already seen a conflicting instantiation of this
+ // declaration (for instance, if there was a prior implicit instantiation).
+ bool Ignored;
+ if (PrevDecl && SemaRef.CheckSpecializationInstantiationRedecl(
+ D->getLocation(), D->getSpecializationKind(), PrevDecl,
+ PrevDecl->getSpecializationKind(),
+ PrevDecl->getPointOfInstantiation(), Ignored))
+ return nullptr;
- return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos,
- VarTemplateArgsInfo, Converted);
+ return VisitVarTemplateSpecializationDecl(
+ InstVarTemplate, D, InsertPos, VarTemplateArgsInfo, Converted, PrevDecl);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
const TemplateArgumentListInfo &TemplateArgsInfo,
- ArrayRef<TemplateArgument> Converted) {
+ ArrayRef<TemplateArgument> Converted,
+ VarTemplateSpecializationDecl *PrevDecl) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
@@ -3153,8 +3380,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (SubstQualifier(D, Var))
return nullptr;
- SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
- Owner, StartingScope);
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
+ StartingScope, false, PrevDecl);
return Var;
}
@@ -3174,6 +3401,10 @@ Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
return nullptr;
}
+Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
+ llvm_unreachable("Concept definitions cannot reside inside a template");
+}
+
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
llvm_unreachable("Unexpected decl");
}
@@ -3506,7 +3737,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
Qualifiers ThisTypeQuals;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
ThisContext = cast<CXXRecordDecl>(Owner);
- ThisTypeQuals = Method->getTypeQualifiers();
+ ThisTypeQuals = Method->getMethodQualifiers();
}
TypeSourceInfo *NewTInfo
@@ -3633,25 +3864,25 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
Scope.MakeInstantiatedLocalArgPack(PatternParam);
Optional<unsigned> NumArgumentsInExpansion
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
- assert(NumArgumentsInExpansion &&
- "should only be called when all template arguments are known");
- QualType PatternType =
- PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
- for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
- ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
- FunctionParam->setDeclName(PatternParam->getDeclName());
- if (!PatternDecl->getType()->isDependentType()) {
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg);
- QualType T = S.SubstType(PatternType, TemplateArgs,
- FunctionParam->getLocation(),
- FunctionParam->getDeclName());
- if (T.isNull())
- return true;
- FunctionParam->setType(T);
- }
+ if (NumArgumentsInExpansion) {
+ QualType PatternType =
+ PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
+ for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
+ ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+ FunctionParam->setDeclName(PatternParam->getDeclName());
+ if (!PatternDecl->getType()->isDependentType()) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg);
+ QualType T = S.SubstType(PatternType, TemplateArgs,
+ FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
+ if (T.isNull())
+ return true;
+ FunctionParam->setType(T);
+ }
- Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
- ++FParamIdx;
+ Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
+ ++FParamIdx;
+ }
}
}
@@ -3882,9 +4113,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Never instantiate an explicit specialization except if it is a class scope
// explicit specialization.
- TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind();
- if (TSK == TSK_ExplicitSpecialization &&
- !Function->getClassScopeSpecializationPattern())
+ TemplateSpecializationKind TSK =
+ Function->getTemplateSpecializationKindForInstantiation();
+ if (TSK == TSK_ExplicitSpecialization)
return;
// Find the function body that we'll be substituting.
@@ -3939,6 +4170,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
}
+ llvm::TimeTraceScope TimeScope("InstantiateFunction", [&]() {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ Function->getNameForDiagnostic(OS, getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
@@ -4165,7 +4404,19 @@ void Sema::BuildVariableInstantiation(
const MultiLevelTemplateArgumentList &TemplateArgs,
LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner,
LocalInstantiationScope *StartingScope,
- bool InstantiatingVarTemplate) {
+ bool InstantiatingVarTemplate,
+ VarTemplateSpecializationDecl *PrevDeclForVarTemplateSpecialization) {
+ // Instantiating a partial specialization to produce a partial
+ // specialization.
+ bool InstantiatingVarTemplatePartialSpec =
+ isa<VarTemplatePartialSpecializationDecl>(OldVar) &&
+ isa<VarTemplatePartialSpecializationDecl>(NewVar);
+ // Instantiating from a variable template (or partial specialization) to
+ // produce a variable template specialization.
+ bool InstantiatingSpecFromTemplate =
+ isa<VarTemplateSpecializationDecl>(NewVar) &&
+ (OldVar->getDescribedVarTemplate() ||
+ isa<VarTemplatePartialSpecializationDecl>(OldVar));
// If we are instantiating a local extern declaration, the
// instantiation belongs lexically to the containing function.
@@ -4211,8 +4462,11 @@ void Sema::BuildVariableInstantiation(
NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs))
Previous.addDecl(NewPrev);
} else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
- OldVar->hasLinkage())
+ OldVar->hasLinkage()) {
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
+ } else if (PrevDeclForVarTemplateSpecialization) {
+ Previous.addDecl(PrevDeclForVarTemplateSpecialization);
+ }
CheckVariableDeclaration(NewVar, Previous);
if (!InstantiatingVarTemplate) {
@@ -4228,23 +4482,44 @@ void Sema::BuildVariableInstantiation(
// Link instantiations of static data members back to the template from
// which they were instantiated.
- if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate)
+ //
+ // Don't do this when instantiating a template (we link the template itself
+ // back in that case) nor when instantiating a static data member template
+ // (that's not a member specialization).
+ if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate &&
+ !InstantiatingSpecFromTemplate)
NewVar->setInstantiationOfStaticDataMember(OldVar,
TSK_ImplicitInstantiation);
+ // If the pattern is an (in-class) explicit specialization, then the result
+ // is also an explicit specialization.
+ if (VarTemplateSpecializationDecl *OldVTSD =
+ dyn_cast<VarTemplateSpecializationDecl>(OldVar)) {
+ if (OldVTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(OldVTSD))
+ cast<VarTemplateSpecializationDecl>(NewVar)->setSpecializationKind(
+ TSK_ExplicitSpecialization);
+ }
+
// Forward the mangling number from the template to the instantiated decl.
Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
- // 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 &&
- !(OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
- !NewVar->isThisDeclarationADefinition())) ||
- NewVar->getType()->isUndeducedType())
+ // Figure out whether to eagerly instantiate the initializer.
+ if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
+ // We're producing a template. Don't instantiate the initializer yet.
+ } else if (NewVar->getType()->isUndeducedType()) {
+ // We need the type to complete the declaration of the variable.
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+ } else if (InstantiatingSpecFromTemplate ||
+ (OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
+ !NewVar->isThisDeclarationADefinition())) {
+ // Delay instantiation of the initializer for variable template
+ // specializations or inline static data members until a definition of the
+ // variable is needed.
+ } else {
+ InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+ }
// Diagnose unused local variables with dependent types, where the diagnostic
// will have been deferred.
@@ -4344,15 +4619,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
if (Var->isInvalidDecl())
return;
- VarTemplateSpecializationDecl *VarSpec =
- dyn_cast<VarTemplateSpecializationDecl>(Var);
- VarDecl *PatternDecl = nullptr, *Def = nullptr;
+ // Never instantiate an explicitly-specialized entity.
+ TemplateSpecializationKind TSK =
+ Var->getTemplateSpecializationKindForInstantiation();
+ if (TSK == TSK_ExplicitSpecialization)
+ return;
+
+ // Find the pattern and the arguments to substitute into it.
+ VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
+ assert(PatternDecl && "no pattern for templated variable");
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Var);
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
if (VarSpec) {
// If this is a variable template specialization, make sure that it is
- // non-dependent, then find its instantiation pattern.
+ // non-dependent.
bool InstantiationDependent = false;
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
@@ -4360,37 +4643,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
"not type-dependent");
(void)InstantiationDependent;
- // Find the variable initialization that we'll be substituting. If the
- // pattern was instantiated from a member template, look back further to
- // find the real pattern.
- assert(VarSpec->getSpecializedTemplate() &&
- "Specialization without specialized template?");
- llvm::PointerUnion<VarTemplateDecl *,
- VarTemplatePartialSpecializationDecl *> PatternPtr =
- VarSpec->getSpecializedTemplateOrPartial();
- if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
- VarTemplatePartialSpecializationDecl *Tmpl =
- PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
- while (VarTemplatePartialSpecializationDecl *From =
- Tmpl->getInstantiatedFromMember()) {
- if (Tmpl->isMemberSpecialization())
- break;
-
- Tmpl = From;
- }
- PatternDecl = Tmpl;
- } else {
- VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
- while (VarTemplateDecl *From =
- Tmpl->getInstantiatedFromMemberTemplate()) {
- if (Tmpl->isMemberSpecialization())
- break;
-
- Tmpl = From;
- }
- PatternDecl = Tmpl->getTemplatedDecl();
- }
-
// If this is a static data member template, there might be an
// uninstantiated initializer on the declaration. If so, instantiate
// it now.
@@ -4434,20 +4686,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
Local.Exit();
GlobalInstantiations.perform();
}
-
- // Find actual definition
- Def = PatternDecl->getDefinition(getASTContext());
} else {
- // If this is a static data member, find its out-of-line definition.
- assert(Var->isStaticDataMember() && "not a static data member?");
- PatternDecl = Var->getInstantiatedFromStaticDataMember();
-
- assert(PatternDecl && "data member was not instantiated from a template?");
- assert(PatternDecl->isStaticDataMember() && "not a static data member?");
- Def = PatternDecl->getDefinition();
+ assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() &&
+ "not a static data member?");
}
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ VarDecl *Def = PatternDecl->getDefinition(getASTContext());
// 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
@@ -4469,7 +4713,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
}
return;
}
-
}
// FIXME: We need to track the instantiation stack in order to know which
@@ -4481,18 +4724,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
/*Complain*/DefinitionRequired))
return;
-
- // Never instantiate an explicit specialization.
- if (TSK == TSK_ExplicitSpecialization)
- return;
-
// C++11 [temp.explicit]p10:
// Except for inline functions, const variables of literal types, variables
// of reference types, [...] explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
+ //
+ // FIXME: That's not exactly the same as "might be usable in constant
+ // expressions", which only allows constexpr variables and const integral
+ // types, not arbitrary const literal types.
if (TSK == TSK_ExplicitInstantiationDeclaration &&
- !Var->isUsableInConstantExpressions(getASTContext()))
+ !Var->mightBeUsableInConstantExpressions(getASTContext()))
return;
// Make sure to pass the instantiated variable to the consumer at the end.
@@ -5006,7 +5248,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
((ParentDC->isFunctionOrMethod() ||
- isa<OMPDeclareReductionDecl>(ParentDC)) &&
+ isa<OMPDeclareReductionDecl>(ParentDC) ||
+ isa<OMPDeclareMapperDecl>(ParentDC)) &&
ParentDC->isDependentContext()) ||
(isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
// D is a local of some kind. Look into the map of local
@@ -5320,7 +5563,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Check if the most recent declaration has changed the specialization kind
// and removed the need for implicit instantiation.
- switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) {
+ switch (Var->getMostRecentDecl()
+ ->getTemplateSpecializationKindForInstantiation()) {
case TSK_Undeclared:
llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration:
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 0e7fc20d2487..d97626551a41 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -1,9 +1,8 @@
//===------- SemaTemplateVariadic.cpp - C++ Variadic Templates ------------===/
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===/
//
// This file implements semantic analysis for C++0x variadic templates.
@@ -40,11 +39,11 @@ namespace {
unsigned DepthLimit = (unsigned)-1;
void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
- if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) {
+ if (auto *VD = dyn_cast<VarDecl>(ND)) {
// For now, the only problematic case is a generic lambda's templated
// call operator, so we don't need to look for all the other ways we
// could have reached a dependent parameter pack.
- auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
+ auto *FD = dyn_cast<FunctionDecl>(VD->getDeclContext());
auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
return;
@@ -314,11 +313,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
if (N == FunctionScopes.size()) {
- for (auto &Param : Unexpanded) {
- auto *PD = dyn_cast_or_null<ParmVarDecl>(
- Param.first.dyn_cast<NamedDecl *>());
- if (PD && PD->getDeclContext() == LSI->CallOperator)
- LambdaParamPackReferences.push_back(Param);
+ for (auto &Pack : Unexpanded) {
+ auto *VD = dyn_cast_or_null<VarDecl>(
+ Pack.first.dyn_cast<NamedDecl *>());
+ if (VD && VD->getDeclContext() == LSI->CallOperator)
+ LambdaParamPackReferences.push_back(Pack);
}
}
@@ -587,11 +586,15 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
Optional<unsigned> NumExpansions) {
- // C++0x [temp.variadic]p5:
+ // C++11 [temp.variadic]p5:
// The pattern of a pack expansion shall name one or more
// parameter packs that are not expanded by a nested pack
// expansion.
- if (!Pattern->containsUnexpandedParameterPack()) {
+ //
+ // A pattern containing a deduced type can't occur "naturally" but arises in
+ // the desugaring of an init-capture pack.
+ if (!Pattern->containsUnexpandedParameterPack() &&
+ !Pattern->getContainedDeducedType()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< PatternRange;
return QualType();
@@ -616,6 +619,7 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
if (!Pattern->containsUnexpandedParameterPack()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< Pattern->getSourceRange();
+ CorrectDelayedTyposInExpr(Pattern);
return ExprError();
}
@@ -642,7 +646,7 @@ bool Sema::CheckParameterPacksForExpansion(
// Compute the depth and index for this parameter pack.
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
- bool IsFunctionParameterPack = false;
+ bool IsVarDeclPack = false;
if (const TemplateTypeParmType *TTP
= i->first.dyn_cast<const TemplateTypeParmType *>()) {
@@ -651,8 +655,8 @@ bool Sema::CheckParameterPacksForExpansion(
Name = TTP->getIdentifier();
} else {
NamedDecl *ND = i->first.get<NamedDecl *>();
- if (isa<ParmVarDecl>(ND))
- IsFunctionParameterPack = true;
+ if (isa<VarDecl>(ND))
+ IsVarDeclPack = true;
else
std::tie(Depth, Index) = getDepthAndIndex(ND);
@@ -661,7 +665,7 @@ bool Sema::CheckParameterPacksForExpansion(
// Determine the size of this argument pack.
unsigned NewPackSize;
- if (IsFunctionParameterPack) {
+ if (IsVarDeclPack) {
// Figure out whether we're instantiating to an argument pack or not.
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
@@ -695,7 +699,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 && CurrentInstantiationScope) {
+ if (!IsVarDeclPack && CurrentInstantiationScope) {
if (NamedDecl *PartialPack
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
unsigned PartialDepth, PartialIndex;
@@ -779,8 +783,8 @@ Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
Index = TTP->getIndex();
} else {
NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
- if (isa<ParmVarDecl>(ND)) {
- // Function parameter pack.
+ if (isa<VarDecl>(ND)) {
+ // Function parameter pack or init-capture pack.
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
@@ -925,12 +929,16 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
namespace {
// Callback to only accept typo corrections that refer to parameter packs.
-class ParameterPackValidatorCCC : public CorrectionCandidateCallback {
+class ParameterPackValidatorCCC final : public CorrectionCandidateCallback {
public:
bool ValidateCandidate(const TypoCorrection &candidate) override {
NamedDecl *ND = candidate.getCorrectionDecl();
return ND && ND->isParameterPack();
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<ParameterPackValidatorCCC>(*this);
+ }
};
}
@@ -966,18 +974,18 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
break;
case LookupResult::NotFound:
- case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::NotFoundInCurrentInstantiation: {
+ ParameterPackValidatorCCC CCC{};
if (TypoCorrection Corrected =
CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr,
- llvm::make_unique<ParameterPackValidatorCCC>(),
- CTK_ErrorRecovery)) {
+ CCC, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
PDiag(diag::note_parameter_pack_here));
ParameterPack = Corrected.getCorrectionDecl();
}
break;
-
+ }
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
break;
@@ -1081,7 +1089,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr()))
Pack = Subst->getArgumentPack();
else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
- for (ParmVarDecl *PD : *Subst)
+ for (VarDecl *PD : *Subst)
if (PD->isParameterPack())
return None;
return Subst->getNumExpansions();
@@ -1173,15 +1181,18 @@ ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
}
BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator);
- return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc);
+ return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
+ None);
}
ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ Optional<unsigned> NumExpansions) {
return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,
- Operator, EllipsisLoc, RHS, RParenLoc);
+ Operator, EllipsisLoc, RHS, RParenLoc,
+ NumExpansions);
}
ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index b4c075e9c46d..29acf6177eb9 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1,9 +1,8 @@
//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -183,6 +182,10 @@ namespace {
SmallVector<TypeAttrPair, 8> AttrsForTypes;
bool AttrsForTypesSorted = true;
+ /// MacroQualifiedTypes mapping to macro expansion locations that will be
+ /// stored in a MacroQualifiedTypeLoc.
+ llvm::DenseMap<const MacroQualifiedType *, SourceLocation> LocsForMacros;
+
/// Flag to indicate we parsed a noderef attribute. This is used for
/// validating that noderef was used on a pointer or array.
bool parsedNoDeref;
@@ -256,13 +259,27 @@ namespace {
return T;
}
+ /// Completely replace the \c auto in \p TypeWithAuto by
+ /// \p Replacement. Also replace \p TypeWithAuto in \c TypeAttrPair if
+ /// necessary.
+ QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement) {
+ QualType T = sema.ReplaceAutoType(TypeWithAuto, Replacement);
+ if (auto *AttrTy = TypeWithAuto->getAs<AttributedType>()) {
+ // Attributed type still should be an attributed type after replacement.
+ auto *NewAttrTy = cast<AttributedType>(T.getTypePtr());
+ for (TypeAttrPair &A : AttrsForTypes) {
+ if (A.first == AttrTy)
+ A.first = NewAttrTy;
+ }
+ AttrsForTypesSorted = false;
+ }
+ return T;
+ }
+
/// Extract and remove the Attr* for a given attributed type.
const Attr *takeAttrForAttributedType(const AttributedType *AT) {
if (!AttrsForTypesSorted) {
- std::stable_sort(AttrsForTypes.begin(), AttrsForTypes.end(),
- [](const TypeAttrPair &A, const TypeAttrPair &B) {
- return A.first < B.first;
- });
+ llvm::stable_sort(AttrsForTypes, llvm::less_first());
AttrsForTypesSorted = true;
}
@@ -282,6 +299,19 @@ namespace {
llvm_unreachable("no Attr* for AttributedType*");
}
+ SourceLocation
+ getExpansionLocForMacroQualifiedType(const MacroQualifiedType *MQT) const {
+ auto FoundLoc = LocsForMacros.find(MQT);
+ assert(FoundLoc != LocsForMacros.end() &&
+ "Unable to find macro expansion location for MacroQualifedType");
+ return FoundLoc->second;
+ }
+
+ void setExpansionLocForMacroQualifiedType(const MacroQualifiedType *MQT,
+ SourceLocation Loc) {
+ LocsForMacros[MQT] = Loc;
+ }
+
void setParsedNoDeref(bool parsed) { parsedNoDeref = parsed; }
bool didParseNoDeref() const { return parsedNoDeref; }
@@ -518,8 +548,8 @@ static void distributeObjCPointerTypeAttrFromDeclarator(
// attribute from being applied multiple times and gives
// the source-location-filler something to work with.
state.saveDeclSpecAttrs();
- moveAttrFromListToList(attr, declarator.getAttributes(),
- declarator.getMutableDeclSpec().getAttributes());
+ declarator.getMutableDeclSpec().getAttributes().takeOneFrom(
+ declarator.getAttributes(), &attr);
return;
}
}
@@ -721,7 +751,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*IsAmbiguous=*/false,
/*LParenLoc=*/NoLoc,
/*ArgInfo=*/nullptr,
- /*NumArgs=*/0,
+ /*NumParams=*/0,
/*EllipsisLoc=*/NoLoc,
/*RParenLoc=*/NoLoc,
/*RefQualifierIsLvalueRef=*/true,
@@ -1326,7 +1356,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// "At least one type specifier shall be given in the declaration
// specifiers in each declaration, and in the specifier-qualifier list in
// each struct declaration and type name."
- if (S.getLangOpts().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus && !DS.isTypeSpecPipe()) {
S.Diag(DeclLoc, diag::err_missing_type_specifier)
<< DS.getSourceRange();
@@ -1334,7 +1364,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// value being declared, poison it as invalid so we don't get chains of
// errors.
declarator.setInvalidType(true);
- } else if (S.getLangOpts().OpenCLVersion >= 200 && DS.isTypeSpecPipe()){
+ } else if ((S.getLangOpts().OpenCLVersion >= 200 ||
+ S.getLangOpts().OpenCLCPlusPlus) &&
+ DS.isTypeSpecPipe()) {
S.Diag(DeclLoc, diag::err_missing_actual_pipe_type)
<< DS.getSourceRange();
declarator.setInvalidType(true);
@@ -1434,7 +1466,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
}
case DeclSpec::TST_int128:
- if (!S.Context.getTargetInfo().hasInt128Type())
+ if (!S.Context.getTargetInfo().hasInt128Type() &&
+ !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
<< "__int128";
if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned)
@@ -1442,7 +1475,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
else
Result = Context.Int128Ty;
break;
- case DeclSpec::TST_float16: Result = Context.Float16Ty; break;
+ case DeclSpec::TST_float16:
+ // CUDA host and device may have different _Float16 support, therefore
+ // do not diagnose _Float16 usage to avoid false alarm.
+ // ToDo: more precise diagnostics for CUDA.
+ if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA &&
+ !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
+ << "_Float16";
+ Result = Context.Float16Ty;
+ break;
case DeclSpec::TST_half: Result = Context.HalfTy; break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
@@ -1452,7 +1494,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.DoubleTy;
break;
case DeclSpec::TST_float128:
- if (!S.Context.getTargetInfo().hasFloat128Type())
+ if (!S.Context.getTargetInfo().hasFloat128Type() &&
+ !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
<< "__float128";
Result = Context.Float128Ty;
@@ -1868,7 +1911,7 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
}
static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){
- std::string Quals = FnTy->getTypeQuals().getAsString();
+ std::string Quals = FnTy->getMethodQuals().getAsString();
switch (FnTy->getRefQualifier()) {
case RQ_None:
@@ -1910,7 +1953,7 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
QualifiedFunctionKind QFK) {
// Does T refer to a function type with a cv-qualifier or a ref-qualifier?
const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
- if (!FPT || (FPT->getTypeQuals().empty() && FPT->getRefQualifier() == RQ_None))
+ if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
return false;
S.Diag(Loc, diag::err_compound_qualified_function_type)
@@ -2243,15 +2286,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) {
- if (getLangOpts().CUDA) {
- // CUDA device code doesn't support VLAs.
- CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget();
- } else if (!getLangOpts().OpenMP ||
- shouldDiagnoseTargetSupportFromOpenMP()) {
- // Some targets don't support VLAs.
- Diag(Loc, diag::err_vla_unsupported);
- return QualType();
- }
+ // CUDA device code and some other targets don't support VLAs.
+ targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
+ ? diag::err_cuda_vla
+ : diag::err_vla_unsupported)
+ << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
+ ? CurrentCUDATarget()
+ : CFT_InvalidTarget);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
@@ -2415,6 +2456,11 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
return true;
}
+ if (T.hasNonTrivialToPrimitiveDestructCUnion() ||
+ T.hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn,
+ NTCUK_Destruct|NTCUK_Copy);
+
return false;
}
@@ -2913,7 +2959,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
assert(LSI && "No LambdaScopeInfo on the stack!");
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+ const unsigned AutoParameterPosition = LSI->TemplateParams.size();
const bool IsParameterPack = D.hasEllipsis();
// Create the TemplateTypeParmDecl here to retrieve the corresponding
@@ -2925,12 +2971,13 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
/*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
TemplateParameterDepth, AutoParameterPosition,
/*Identifier*/ nullptr, false, IsParameterPack);
- LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ CorrespondingTemplateParam->setImplicit();
+ LSI->TemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
// template type parameter.
// FIXME: Retain some type sugar to indicate that this was written
// as 'auto'.
- T = SemaRef.ReplaceAutoType(
+ T = state.ReplaceAutoType(
T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
}
break;
@@ -3916,6 +3963,25 @@ static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr,
llvm_unreachable("unknown NullabilityKind");
}
+// Diagnose whether this is a case with the multiple addr spaces.
+// Returns true if this is an invalid case.
+// ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified
+// by qualifiers for two or more different address spaces."
+static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
+ LangAS ASNew,
+ SourceLocation AttrLoc) {
+ if (ASOld != LangAS::Default) {
+ if (ASOld != ASNew) {
+ S.Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers);
+ return true;
+ }
+ // Emit a warning if they are identical; it's likely unintended.
+ S.Diag(AttrLoc,
+ diag::warn_attribute_address_multiple_identical_qualifiers);
+ }
+ return false;
+}
+
static TypeSourceInfo *
GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
QualType T, TypeSourceInfo *ReturnTypeInfo);
@@ -3944,7 +4010,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Does T refer to a function type with a cv-qualifier or a ref-qualifier?
bool IsQualifiedFunction = T->isFunctionProtoType() &&
- (!T->castAs<FunctionProtoType>()->getTypeQuals().empty() ||
+ (!T->castAs<FunctionProtoType>()->getMethodQuals().empty() ||
T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None);
// If T is 'decltype(auto)', the only declarators we can have are parens
@@ -4194,7 +4260,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
auto inferPointerNullability =
[&](SimplePointerKind pointerKind, SourceLocation pointerLoc,
SourceLocation pointerEndLoc,
- ParsedAttributesView &attrs) -> ParsedAttr * {
+ ParsedAttributesView &attrs, AttributePool &Pool) -> ParsedAttr * {
// We've seen a pointer.
if (NumPointersRemaining > 0)
--NumPointersRemaining;
@@ -4208,11 +4274,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
ParsedAttr::Syntax syntax = inferNullabilityCS
? ParsedAttr::AS_ContextSensitiveKeyword
: ParsedAttr::AS_Keyword;
- ParsedAttr *nullabilityAttr =
- state.getDeclarator().getAttributePool().create(
- S.getNullabilityKeyword(*inferNullability),
- SourceRange(pointerLoc), nullptr, SourceLocation(), nullptr, 0,
- syntax);
+ ParsedAttr *nullabilityAttr = Pool.create(
+ S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc),
+ nullptr, SourceLocation(), nullptr, 0, syntax);
attrs.addAtEnd(nullabilityAttr);
@@ -4271,7 +4335,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (auto *attr = inferPointerNullability(
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
D.getDeclSpec().getEndLoc(),
- D.getMutableDeclSpec().getAttributes())) {
+ D.getMutableDeclSpec().getAttributes(),
+ D.getMutableDeclSpec().getAttributePool())) {
T = state.getAttributedType(
createNullabilityAttr(Context, *attr, *inferNullability), T, T);
}
@@ -4311,7 +4376,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Handle pointer nullability.
inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc,
- DeclType.EndLoc, DeclType.getAttrs());
+ DeclType.EndLoc, DeclType.getAttrs(),
+ state.getDeclarator().getAttributePool());
T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) {
@@ -4333,7 +4399,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Handle pointer nullability
inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc,
- DeclType.EndLoc, DeclType.getAttrs());
+ DeclType.EndLoc, DeclType.getAttrs(),
+ state.getDeclarator().getAttributePool());
if (LangOpts.ObjC && T->getAs<ObjCObjectType>()) {
T = Context.getObjCObjectPointerType(T);
@@ -4454,7 +4521,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the function declarator has a prototype (i.e. it is not () and
// does not have a K&R-style identifier list), then the arguments are part
// of the type, otherwise the argument list is ().
- const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
IsQualifiedFunction =
FTI.hasMethodTypeQualifiers() || FTI.hasRefQualifier();
@@ -4558,7 +4625,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isVariadic &&
!(D.getIdentifier() &&
((D.getIdentifier()->getName() == "printf" &&
- LangOpts.OpenCLVersion >= 120) ||
+ (LangOpts.OpenCLCPlusPlus || LangOpts.OpenCLVersion >= 120)) ||
D.getIdentifier()->getName().startswith("__")))) {
S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function);
D.setInvalidType(true);
@@ -4823,18 +4890,35 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI.ExceptionSpec);
- const auto &Spec = D.getCXXScopeSpec();
+ // FIXME: Set address space from attrs for C++ mode here.
// OpenCLCPlusPlus: A class member function has an address space.
- if (state.getSema().getLangOpts().OpenCLCPlusPlus &&
- ((!Spec.isEmpty() &&
- Spec.getScopeRep()->getKind() == NestedNameSpecifier::TypeSpec) ||
- state.getDeclarator().getContext() ==
- DeclaratorContext::MemberContext)) {
- LangAS CurAS = EPI.TypeQuals.getAddressSpace();
+ auto IsClassMember = [&]() {
+ return (!state.getDeclarator().getCXXScopeSpec().isEmpty() &&
+ state.getDeclarator()
+ .getCXXScopeSpec()
+ .getScopeRep()
+ ->getKind() == NestedNameSpecifier::TypeSpec) ||
+ state.getDeclarator().getContext() ==
+ DeclaratorContext::MemberContext;
+ };
+
+ if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) {
+ LangAS ASIdx = LangAS::Default;
+ // Take address space attr if any and mark as invalid to avoid adding
+ // them later while creating QualType.
+ if (FTI.MethodQualifiers)
+ for (ParsedAttr &attr : FTI.MethodQualifiers->getAttributes()) {
+ LangAS ASIdxNew = attr.asOpenCLLangAS();
+ if (DiagnoseMultipleAddrSpaceAttributes(S, ASIdx, ASIdxNew,
+ attr.getLoc()))
+ D.setInvalidType(true);
+ else
+ ASIdx = ASIdxNew;
+ }
// If a class member function's address space is not set, set it to
// __generic.
LangAS AS =
- (CurAS == LangAS::Default ? LangAS::opencl_generic : CurAS);
+ (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx);
EPI.TypeQuals.addAddressSpace(AS);
}
T = Context.getFunctionType(T, ParamTys, EPI);
@@ -4848,7 +4932,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Handle pointer nullability.
inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc,
- DeclType.EndLoc, DeclType.getAttrs());
+ DeclType.EndLoc, DeclType.getAttrs(),
+ state.getDeclarator().getAttributePool());
if (SS.isInvalid()) {
// Avoid emitting extra errors if we already errored on the scope.
@@ -4918,11 +5003,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
processTypeAttrs(state, T, TAL_DeclChunk, DeclType.getAttrs());
if (DeclType.Kind != DeclaratorChunk::Paren) {
- if (ExpectNoDerefChunk) {
- if (!IsNoDerefableChunk(DeclType))
- S.Diag(DeclType.Loc, diag::warn_noderef_on_non_pointer_or_array);
- ExpectNoDerefChunk = false;
- }
+ if (ExpectNoDerefChunk && !IsNoDerefableChunk(DeclType))
+ S.Diag(DeclType.Loc, diag::warn_noderef_on_non_pointer_or_array);
ExpectNoDerefChunk = state.didParseNoDeref();
}
@@ -4949,7 +5031,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
break;
case DeclaratorChunk::Function: {
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
- if (FTI.NumParams == 0 && !FTI.isVariadic)
+ // We supress the warning when there's no LParen location, as this
+ // indicates the declaration was an implicit declaration, which gets
+ // warned about separately via -Wimplicit-function-declaration.
+ if (FTI.NumParams == 0 && !FTI.isVariadic && FTI.getLParenLoc().isValid())
S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
<< IsBlock
<< FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
@@ -5066,7 +5151,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p9:
// A constexpr specifier used in an object declaration declares the object
// as const.
- if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) {
+ if (D.getDeclSpec().hasConstexprSpecifier() && T->isObjectType()) {
T.addConst();
}
@@ -5310,6 +5395,11 @@ namespace {
Visit(TL.getModifiedLoc());
fillAttributedTypeLoc(TL, State);
}
+ void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
+ Visit(TL.getInnerLoc());
+ TL.setExpansionLoc(
+ State.getExpansionLocForMacroQualifiedType(TL.getTypePtr()));
+ }
void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
Visit(TL.getUnqualifiedLoc());
}
@@ -5583,6 +5673,9 @@ namespace {
assert(Chunk.Kind == DeclaratorChunk::Pipe);
TL.setKWLoc(Chunk.Loc);
}
+ void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
+ TL.setExpansionLoc(Chunk.Loc);
+ }
void VisitTypeLoc(TypeLoc TL) {
llvm_unreachable("unsupported TypeLoc kind in declarator!");
@@ -5661,6 +5754,12 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
}
+ while (MacroQualifiedTypeLoc TL = CurrTL.getAs<MacroQualifiedTypeLoc>()) {
+ TL.setExpansionLoc(
+ State.getExpansionLocForMacroQualifiedType(TL.getTypePtr()));
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ }
+
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
fillAttributedTypeLoc(TL, State);
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
@@ -5752,28 +5851,27 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) {
// Type Attribute Processing
//===----------------------------------------------------------------------===//
-/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression
-/// is uninstantiated. If instantiated it will apply the appropriate address space
-/// to the type. This function allows dependent template variables to be used in
-/// conjunction with the address_space attribute
-QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
- SourceLocation AttrLoc) {
+/// Build an AddressSpace index from a constant expression and diagnose any
+/// errors related to invalid address_spaces. Returns true on successfully
+/// building an AddressSpace index.
+static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx,
+ const Expr *AddrSpace,
+ SourceLocation AttrLoc) {
if (!AddrSpace->isValueDependent()) {
-
llvm::APSInt addrSpace(32);
- if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) {
- Diag(AttrLoc, diag::err_attribute_argument_type)
+ if (!AddrSpace->isIntegerConstantExpr(addrSpace, S.Context)) {
+ S.Diag(AttrLoc, diag::err_attribute_argument_type)
<< "'address_space'" << AANT_ArgumentIntegerConstant
<< AddrSpace->getSourceRange();
- return QualType();
+ return false;
}
// Bounds checking.
if (addrSpace.isSigned()) {
if (addrSpace.isNegative()) {
- Diag(AttrLoc, diag::err_attribute_address_space_negative)
+ S.Diag(AttrLoc, diag::err_attribute_address_space_negative)
<< AddrSpace->getSourceRange();
- return QualType();
+ return false;
}
addrSpace.setIsSigned(false);
}
@@ -5782,27 +5880,31 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
max =
Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace;
if (addrSpace > max) {
- Diag(AttrLoc, diag::err_attribute_address_space_too_high)
+ S.Diag(AttrLoc, diag::err_attribute_address_space_too_high)
<< (unsigned)max.getZExtValue() << AddrSpace->getSourceRange();
- return QualType();
+ return false;
}
- LangAS ASIdx =
+ ASIdx =
getLangASFromTargetAS(static_cast<unsigned>(addrSpace.getZExtValue()));
+ return true;
+ }
- // If this type is already address space qualified with a different
- // address space, reject it.
- // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified
- // by qualifiers for two or more different address spaces."
- if (T.getAddressSpace() != LangAS::Default) {
- if (T.getAddressSpace() != ASIdx) {
- Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers);
- return QualType();
- } else
- // Emit a warning if they are identical; it's likely unintended.
- Diag(AttrLoc,
- diag::warn_attribute_address_multiple_identical_qualifiers);
- }
+ // Default value for DependentAddressSpaceTypes
+ ASIdx = LangAS::Default;
+ return true;
+}
+
+/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression
+/// is uninstantiated. If instantiated it will apply the appropriate address
+/// space to the type. This function allows dependent template variables to be
+/// used in conjunction with the address_space attribute
+QualType Sema::BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace,
+ SourceLocation AttrLoc) {
+ if (!AddrSpace->isValueDependent()) {
+ if (DiagnoseMultipleAddrSpaceAttributes(*this, T.getAddressSpace(), ASIdx,
+ AttrLoc))
+ return QualType();
return Context.getAddrSpaceQualType(T, ASIdx);
}
@@ -5820,6 +5922,14 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
return Context.getDependentAddressSpaceType(T, AddrSpace, AttrLoc);
}
+QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
+ SourceLocation AttrLoc) {
+ LangAS ASIdx;
+ if (!BuildAddressSpaceIndex(*this, ASIdx, AddrSpace, AttrLoc))
+ return QualType();
+ return BuildAddressSpaceAttr(T, ASIdx, AddrSpace, AttrLoc);
+}
+
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
/// specified type. The attribute contains 1 argument, the id of the address
/// space for the type.
@@ -5856,7 +5966,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
ExprResult AddrSpace = S.ActOnIdExpression(
- S.getCurScope(), SS, TemplateKWLoc, id, false, false);
+ S.getCurScope(), SS, TemplateKWLoc, id, /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
if (AddrSpace.isInvalid())
return;
@@ -5865,49 +5976,51 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
}
- // Create the DependentAddressSpaceType or append an address space onto
- // the type.
- QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc());
+ LangAS ASIdx;
+ if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) {
+ Attr.setInvalid();
+ return;
+ }
- if (!T.isNull()) {
- ASTContext &Ctx = S.Context;
- auto *ASAttr = ::new (Ctx) AddressSpaceAttr(
- Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(),
- static_cast<unsigned>(T.getQualifiers().getAddressSpace()));
- Type = State.getAttributedType(ASAttr, T, T);
+ ASTContext &Ctx = S.Context;
+ auto *ASAttr = ::new (Ctx) AddressSpaceAttr(
+ Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(),
+ static_cast<unsigned>(ASIdx));
+
+ // If the expression is not value dependent (not templated), then we can
+ // apply the address space qualifiers just to the equivalent type.
+ // Otherwise, we make an AttributedType with the modified and equivalent
+ // type the same, and wrap it in a DependentAddressSpaceType. When this
+ // dependent type is resolved, the qualifier is added to the equivalent type
+ // later.
+ QualType T;
+ if (!ASArgExpr->isValueDependent()) {
+ QualType EquivType =
+ S.BuildAddressSpaceAttr(Type, ASIdx, ASArgExpr, Attr.getLoc());
+ if (EquivType.isNull()) {
+ Attr.setInvalid();
+ return;
+ }
+ T = State.getAttributedType(ASAttr, Type, EquivType);
} else {
- Attr.setInvalid();
+ T = State.getAttributedType(ASAttr, Type, Type);
+ T = S.BuildAddressSpaceAttr(T, ASIdx, ASArgExpr, Attr.getLoc());
}
+
+ if (!T.isNull())
+ Type = T;
+ else
+ Attr.setInvalid();
} else {
// The keyword-based type attributes imply which address space to use.
- switch (Attr.getKind()) {
- case ParsedAttr::AT_OpenCLGlobalAddressSpace:
- ASIdx = LangAS::opencl_global; break;
- case ParsedAttr::AT_OpenCLLocalAddressSpace:
- ASIdx = LangAS::opencl_local; break;
- case ParsedAttr::AT_OpenCLConstantAddressSpace:
- ASIdx = LangAS::opencl_constant; break;
- case ParsedAttr::AT_OpenCLGenericAddressSpace:
- ASIdx = LangAS::opencl_generic; break;
- case ParsedAttr::AT_OpenCLPrivateAddressSpace:
- ASIdx = LangAS::opencl_private; break;
- default:
+ ASIdx = Attr.asOpenCLLangAS();
+ if (ASIdx == LangAS::Default)
llvm_unreachable("Invalid address space");
- }
- // If this type is already address space qualified with a different
- // address space, reject it.
- // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by
- // qualifiers for two or more different address spaces."
- if (Type.getAddressSpace() != LangAS::Default) {
- if (Type.getAddressSpace() != ASIdx) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
- Attr.setInvalid();
- return;
- } else
- // Emit a warning if they are identical; it's likely unintended.
- S.Diag(Attr.getLoc(),
- diag::warn_attribute_address_multiple_identical_qualifiers);
+ if (DiagnoseMultipleAddrSpaceAttributes(S, Type.getAddressSpace(), ASIdx,
+ Attr.getLoc())) {
+ Attr.setInvalid();
+ return;
}
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
@@ -6837,6 +6950,57 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
}
+ if (attr.getKind() == ParsedAttr::AT_NoThrow) {
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ if (S.CheckAttrNoArgs(attr)) {
+ attr.setInvalid();
+ return true;
+ }
+
+ // Otherwise we can process right away.
+ auto *Proto = unwrapped.get()->castAs<FunctionProtoType>();
+
+ // MSVC ignores nothrow if it is in conflict with an explicit exception
+ // specification.
+ if (Proto->hasExceptionSpec()) {
+ switch (Proto->getExceptionSpecType()) {
+ case EST_None:
+ llvm_unreachable("This doesn't have an exception spec!");
+
+ case EST_DynamicNone:
+ case EST_BasicNoexcept:
+ case EST_NoexceptTrue:
+ case EST_NoThrow:
+ // Exception spec doesn't conflict with nothrow, so don't warn.
+ LLVM_FALLTHROUGH;
+ case EST_Unparsed:
+ case EST_Uninstantiated:
+ case EST_DependentNoexcept:
+ case EST_Unevaluated:
+ // We don't have enough information to properly determine if there is a
+ // conflict, so suppress the warning.
+ break;
+ case EST_Dynamic:
+ case EST_MSAny:
+ case EST_NoexceptFalse:
+ S.Diag(attr.getLoc(), diag::warn_nothrow_attribute_ignored);
+ break;
+ }
+ return true;
+ }
+
+ type = unwrapped.wrap(
+ S, S.Context
+ .getFunctionTypeWithExceptionSpec(
+ QualType{Proto, 0},
+ FunctionProtoType::ExceptionSpecInfo{EST_NoThrow})
+ ->getAs<FunctionType>());
+ return true;
+ }
+
// Delay if the type didn't work out to a function.
if (!unwrapped.isFunctionType()) return false;
@@ -6871,19 +7035,16 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
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.
- bool IsInvalid = true;
- if (CC == CC_X86StdCall || CC == CC_X86FastCall) {
- DiagID = diag::warn_cconv_varargs;
- IsInvalid = false;
- }
+ if (CC == CC_X86StdCall || CC == CC_X86FastCall)
+ return S.Diag(attr.getLoc(), diag::warn_cconv_unsupported)
+ << FunctionType::getNameForCallConv(CC)
+ << (int)Sema::CallingConventionIgnoredReason::VariadicFunction;
- S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC);
- if (IsInvalid) attr.setInvalid();
- return true;
+ attr.setInvalid();
+ return S.Diag(attr.getLoc(), diag::err_cconv_varargs)
+ << FunctionType::getNameForCallConv(CC);
}
}
@@ -6910,12 +7071,16 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
}
-bool Sema::hasExplicitCallingConv(QualType &T) {
- QualType R = T.IgnoreParens();
- while (const AttributedType *AT = dyn_cast<AttributedType>(R)) {
+bool Sema::hasExplicitCallingConv(QualType T) {
+ const AttributedType *AT;
+
+ // Stop if we'd be stripping off a typedef sugar node to reach the
+ // AttributedType.
+ while ((AT = T->getAs<AttributedType>()) &&
+ AT->getAs<TypedefType>() == T->getAs<TypedefType>()) {
if (AT->isCallingConv())
return true;
- R = AT->getModifiedType().IgnoreParens();
+ T = AT->getModifiedType();
}
return false;
}
@@ -6938,8 +7103,9 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
// Issue a warning on ignored calling convention -- except of __stdcall.
// Again, this is what MS compiler does.
if (CurCC != CC_X86StdCall)
- Diag(Loc, diag::warn_cconv_structors)
- << FunctionType::getNameForCallConv(CurCC);
+ Diag(Loc, diag::warn_cconv_unsupported)
+ << FunctionType::getNameForCallConv(CurCC)
+ << (int)Sema::CallingConventionIgnoredReason::ConstructorDestructor;
// Default adjustment.
} else {
// Only adjust types with the default convention. For example, on Windows
@@ -6986,7 +7152,8 @@ static void HandleVectorSizeAttr(QualType &CurType, const ParsedAttr &Attr,
Id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc,
- Id, false, false);
+ Id, /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
if (Size.isInvalid())
return;
@@ -7023,7 +7190,8 @@ static void HandleExtVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc,
- id, false, false);
+ id, /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
if (Size.isInvalid())
return;
@@ -7234,8 +7402,13 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
// otherwise it will fail some sema check.
IsFuncReturnType || IsFuncType ||
// Do not deduce addr space for member types of struct, except the pointee
- // type of a pointer member type.
- (D.getContext() == DeclaratorContext::MemberContext && !IsPointee) ||
+ // type of a pointer member type or static data members.
+ (D.getContext() == DeclaratorContext::MemberContext &&
+ (!IsPointee &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)) ||
+ // Do not deduce addr space of non-pointee in type alias because it
+ // doesn't define any object.
+ (D.getContext() == DeclaratorContext::AliasDeclContext && !IsPointee) ||
// Do not deduce addr space for types used to define a typedef and the
// typedef itself, except the pointee type of a pointer type which is used
// to define the typedef.
@@ -7244,9 +7417,28 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
// Do not deduce addr space of the void type, e.g. in f(void), otherwise
// it will fail some sema check.
(T->isVoidType() && !IsPointee) ||
- // Do not deduce address spaces for dependent types because they might end
+ // Do not deduce addr spaces for dependent types because they might end
// up instantiating to a type with an explicit address space qualifier.
- T->isDependentType())
+ // Except for pointer or reference types because the addr space in
+ // template argument can only belong to a pointee.
+ (T->isDependentType() && !T->isPointerType() && !T->isReferenceType()) ||
+ // Do not deduce addr space of decltype because it will be taken from
+ // its argument.
+ T->isDecltypeType() ||
+ // OpenCL spec v2.0 s6.9.b:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ // OpenCL spec v2.0 s6.13.14:
+ // Samplers can also be declared as global constants in the program
+ // source using the following syntax.
+ // const sampler_t <sampler name> = <value>
+ // In codegen, file-scope sampler type variable has special handing and
+ // does not rely on address space qualifier. On the other hand, deducing
+ // address space of const sampler file-scope variable as global address
+ // space causes spurious diagnostic about __global address space
+ // qualifier, therefore do not deduce address space of file-scope sampler
+ // type variable.
+ (D.getContext() == DeclaratorContext::FileContext && T->isSamplerT()))
return;
LangAS ImpAddr = LangAS::Default;
@@ -7338,9 +7530,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (!IsTypeAttr)
continue;
}
- } else if (TAL != TAL_DeclChunk) {
+ } else if (TAL != TAL_DeclChunk &&
+ attr.getKind() != ParsedAttr::AT_AddressSpace) {
// Otherwise, only consider type processing for a C++11 attribute if
// it's actually been applied to a type.
+ // We also allow C++11 address_space attributes to pass through.
continue;
}
}
@@ -7444,7 +7638,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
state.getDeclarator().isPrototypeContext() &&
!hasOuterPointerLikeChunk(state.getDeclarator(), endIndex);
if (checkNullabilityTypeSpecifier(
- state,
+ state,
type,
attr,
allowOnArrayType)) {
@@ -7477,6 +7671,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setInvalid();
break;
+ case ParsedAttr::AT_NoThrow:
+ // Exception Specifications aren't generally supported in C mode throughout
+ // clang, so revert to attribute-based handling for C.
+ if (!state.getSema().getLangOpts().CPlusPlus)
+ break;
+ LLVM_FALLTHROUGH;
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
@@ -7490,6 +7690,20 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
distributeFunctionTypeAttr(state, attr, type);
break;
}
+
+ // Handle attributes that are defined in a macro. We do not want this to be
+ // applied to ObjC builtin attributes.
+ if (isa<AttributedType>(type) && attr.hasMacroIdentifier() &&
+ !type.getQualifiers().hasObjCLifetime() &&
+ !type.getQualifiers().hasObjCGCAttr() &&
+ attr.getKind() != ParsedAttr::AT_ObjCGC &&
+ attr.getKind() != ParsedAttr::AT_ObjCOwnership) {
+ const IdentifierInfo *MacroII = attr.getMacroIdentifier();
+ type = state.getSema().Context.getMacroQualifiedType(type, MacroII);
+ state.setExpansionLocForMacroQualifiedType(
+ cast<MacroQualifiedType>(type.getTypePtr()),
+ attr.getMacroExpansionLoc());
+ }
}
if (!state.getSema().getLangOpts().OpenCL ||
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index df14768cbe81..8df18b5c2784 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1,9 +1,8 @@
//===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===//
//
// This file implements a semantic tree transformation that takes a given
@@ -149,6 +148,11 @@ public:
/// statement node appears at most once in its containing declaration.
bool AlwaysRebuild() { return SemaRef.ArgumentPackSubstitutionIndex != -1; }
+ /// Whether the transformation is forming an expression or statement that
+ /// replaces the original. In this case, we'll reuse mangling numbers from
+ /// existing lambdas.
+ bool ReplacingOriginal() { return false; }
+
/// Returns the location of the entity being transformed, if that
/// information was not available elsewhere in the AST.
///
@@ -319,6 +323,13 @@ public:
TypeSourceInfo *TransformTypeWithDeducedTST(TypeSourceInfo *DI);
/// @}
+ /// The reason why the value of a statement is not discarded, if any.
+ enum StmtDiscardKind {
+ SDK_Discarded,
+ SDK_NotDiscarded,
+ SDK_StmtExprResult,
+ };
+
/// Transform the given statement.
///
/// By default, this routine transforms a statement by delegating to the
@@ -328,7 +339,7 @@ public:
/// other mechanism.
///
/// \returns the transformed statement.
- StmtResult TransformStmt(Stmt *S, bool DiscardedValue = false);
+ StmtResult TransformStmt(Stmt *S, StmtDiscardKind SDK = SDK_Discarded);
/// Transform the given statement.
///
@@ -444,8 +455,10 @@ public:
/// TransformDefinition. However, in some cases (e.g., lambda expressions),
/// the transformer itself has to transform the declarations. This routine
/// can be overridden by a subclass that keeps track of such mappings.
- void transformedLocalDecl(Decl *Old, Decl *New) {
- TransformedLocalDecls[Old] = New;
+ void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> New) {
+ assert(New.size() == 1 &&
+ "must override transformedLocalDecl if performing pack expansion");
+ TransformedLocalDecls[Old] = New.front();
}
/// Transform the definition of the given declaration.
@@ -646,6 +659,12 @@ public:
Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
+ /// Transform the body of a lambda-expression.
+ StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body);
+ /// Alternative implementation of TransformLambdaBody that skips transforming
+ /// the body.
+ StmtResult SkipLambdaBody(LambdaExpr *E, Stmt *Body);
+
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
@@ -673,6 +692,9 @@ public:
#define STMT(Node, Parent) \
LLVM_ATTRIBUTE_NOINLINE \
StmtResult Transform##Node(Node *S);
+#define VALUESTMT(Node, Parent) \
+ LLVM_ATTRIBUTE_NOINLINE \
+ StmtResult Transform##Node(Node *S, StmtDiscardKind SDK);
#define EXPR(Node, Parent) \
LLVM_ATTRIBUTE_NOINLINE \
ExprResult Transform##Node(Node *E);
@@ -874,6 +896,12 @@ public:
return SemaRef.Context.getTypeDeclType(Typedef);
}
+ /// Build a new MacroDefined type.
+ QualType RebuildMacroQualifiedType(QualType T,
+ const IdentifierInfo *MacroII) {
+ return SemaRef.Context.getMacroQualifiedType(T, MacroII);
+ }
+
/// Build a new class/struct/union type.
QualType RebuildRecordType(RecordDecl *Record) {
return SemaRef.Context.getTypeDeclType(Record);
@@ -1356,10 +1384,11 @@ public:
unsigned NumInputs, IdentifierInfo **Names,
MultiExprArg Constraints, MultiExprArg Exprs,
Expr *AsmString, MultiExprArg Clobbers,
+ unsigned NumLabels,
SourceLocation RParenLoc) {
return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs,
- AsmString, Clobbers, RParenLoc);
+ AsmString, Clobbers, NumLabels, RParenLoc);
}
/// Build a new MS style inline asm statement.
@@ -1545,6 +1574,16 @@ public:
return getSema().ActOnOpenMPSimdlenClause(Len, StartLoc, LParenLoc, EndLoc);
}
+ /// Build a new OpenMP 'allocator' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPAllocatorClause(Expr *A, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPAllocatorClause(A, StartLoc, LParenLoc, EndLoc);
+ }
+
/// Build a new OpenMP 'collapse' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -1795,17 +1834,30 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *
- RebuildOMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc,
- OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
- SourceLocation MapLoc, SourceLocation ColonLoc,
- ArrayRef<Expr *> VarList, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc) {
+ OMPClause *RebuildOMPMapClause(
+ ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ ArrayRef<SourceLocation> MapTypeModifiersLoc,
+ CXXScopeSpec MapperIdScopeSpec, DeclarationNameInfo MapperId,
+ OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
+ SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
return getSema().ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc,
- MapType, IsMapTypeImplicit, MapLoc,
- ColonLoc, VarList, StartLoc,
- LParenLoc, EndLoc);
+ MapperIdScopeSpec, MapperId, MapType,
+ IsMapTypeImplicit, MapLoc, ColonLoc,
+ VarList, Locs, UnresolvedMappers);
+ }
+
+ /// Build a new OpenMP 'allocate' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPAllocateClause(Expr *Allocate, ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPAllocateClause(Allocate, VarList, StartLoc,
+ LParenLoc, ColonLoc, EndLoc);
}
/// Build a new OpenMP 'num_teams' clause.
@@ -1892,10 +1944,12 @@ public:
/// 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);
+ CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperId,
+ const OMPVarListLocTy &Locs,
+ ArrayRef<Expr *> UnresolvedMappers) {
+ return getSema().ActOnOpenMPToClause(VarList, MapperIdScopeSpec, MapperId,
+ Locs, UnresolvedMappers);
}
/// Build a new OpenMP 'from' clause.
@@ -1903,11 +1957,12 @@ public:
/// 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);
+ CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperId,
+ const OMPVarListLocTy &Locs,
+ ArrayRef<Expr *> UnresolvedMappers) {
+ return getSema().ActOnOpenMPFromClause(VarList, MapperIdScopeSpec, MapperId,
+ Locs, UnresolvedMappers);
}
/// Build a new OpenMP 'use_device_ptr' clause.
@@ -1915,11 +1970,8 @@ public:
/// 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);
+ const OMPVarListLocTy &Locs) {
+ return getSema().ActOnOpenMPUseDevicePtrClause(VarList, Locs);
}
/// Build a new OpenMP 'is_device_ptr' clause.
@@ -1927,11 +1979,8 @@ public:
/// 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);
+ const OMPVarListLocTy &Locs) {
+ return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs);
}
/// Rebuild the operand to an Objective-C \@synchronized statement.
@@ -2232,8 +2281,8 @@ public:
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig = nullptr) {
- return getSema().ActOnCallExpr(/*Scope=*/nullptr, Callee, LParenLoc,
- Args, RParenLoc, ExecConfig);
+ return getSema().BuildCallExpr(/*Scope=*/nullptr, Callee, LParenLoc, Args,
+ RParenLoc, ExecConfig);
}
/// Build a new member access expression.
@@ -2603,6 +2652,16 @@ public:
ListInitialization);
}
+ /// Build a new C++ __builtin_bit_cast expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildBuiltinBitCastExpr(SourceLocation KWLoc,
+ TypeSourceInfo *TSI, Expr *Sub,
+ SourceLocation RParenLoc) {
+ return getSema().BuildBuiltinBitCastExpr(KWLoc, TSI, Sub, RParenLoc);
+ }
+
/// Build a new C++ typeid(type) expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2660,8 +2719,7 @@ public:
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
- getSema().CheckCXXThisCapture(ThisLoc);
- return new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, isImplicit);
+ return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit);
}
/// Build a new C++ throw expression.
@@ -2678,9 +2736,9 @@ public:
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide different behavior.
- ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc,
- ParmVarDecl *Param) {
- return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param);
+ ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) {
+ return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param,
+ getSema().CurContext);
}
/// Build a new C++11 default-initialization expression.
@@ -2690,7 +2748,8 @@ public:
/// routine to provide different behavior.
ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc,
FieldDecl *Field) {
- return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field);
+ return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field,
+ getSema().CurContext);
}
/// Build a new C++ zero-initialization expression.
@@ -2716,7 +2775,7 @@ public:
SourceRange TypeIdParens,
QualType AllocatedType,
TypeSourceInfo *AllocatedTypeInfo,
- Expr *ArraySize,
+ Optional<Expr *> ArraySize,
SourceRange DirectInitRange,
Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
@@ -2944,6 +3003,18 @@ public:
RParenLoc, Length, PartialArgs);
}
+ /// Build a new expression representing a call to a source location
+ /// builtin.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
+ SourceLocation BuiltinLoc,
+ SourceLocation RPLoc,
+ DeclContext *ParentContext) {
+ return getSema().BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, ParentContext);
+ }
+
/// Build a new Objective-C boxed expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -3219,9 +3290,10 @@ public:
ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ Optional<unsigned> NumExpansions) {
return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc,
- RHS, RParenLoc);
+ RHS, RParenLoc, NumExpansions);
}
/// Build an empty C++1z fold-expression with the given operator.
@@ -3270,7 +3342,7 @@ private:
};
template <typename Derived>
-StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, bool DiscardedValue) {
+StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, StmtDiscardKind SDK) {
if (!S)
return S;
@@ -3278,8 +3350,12 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, bool DiscardedValue) {
case Stmt::NoStmtClass: break;
// Transform individual statement nodes
+ // Pass SDK into statements that can produce a value
#define STMT(Node, Parent) \
case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S));
+#define VALUESTMT(Node, Parent) \
+ case Stmt::Node##Class: \
+ return getDerived().Transform##Node(cast<Node>(S), SDK);
#define ABSTRACT_STMT(Node)
#define EXPR(Node, Parent)
#include "clang/AST/StmtNodes.inc"
@@ -3291,10 +3367,10 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, bool DiscardedValue) {
#include "clang/AST/StmtNodes.inc"
{
ExprResult E = getDerived().TransformExpr(cast<Expr>(S));
- if (E.isInvalid())
- return StmtError();
- return getSema().ActOnExprStmt(E, DiscardedValue);
+ if (SDK == SDK_StmtExprResult)
+ E = getSema().ActOnStmtExprResult(E);
+ return getSema().ActOnExprStmt(E, SDK == SDK_Discarded);
}
}
@@ -3879,10 +3955,6 @@ template<typename Derived>
bool TreeTransform<Derived>::TransformTemplateArgument(
const TemplateArgumentLoc &Input,
TemplateArgumentLoc &Output, bool Uneval) {
- EnterExpressionEvaluationContext EEEC(
- SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
- /*LambdaContextDecl=*/nullptr, /*ExprContext=*/
- Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument);
const TemplateArgument &Arg = Input.getArgument();
switch (Arg.getKind()) {
case TemplateArgument::Null:
@@ -3931,9 +4003,11 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
case TemplateArgument::Expression: {
// Template argument expressions are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
- getSema(), Uneval
- ? Sema::ExpressionEvaluationContext::Unevaluated
- : Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ getSema(),
+ Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
+ : Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ /*LambdaContextDecl=*/nullptr, /*ExprContext=*/
+ Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument);
Expr *InputExpr = Input.getSourceExpression();
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
@@ -4462,6 +4536,14 @@ QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB,
return Result;
}
+/// Helper to deduce addr space of a pointee type in OpenCL mode.
+/// If the type is updated it will be overwritten in PointeeType param.
+static void deduceOpenCLPointeeAddrSpace(Sema &SemaRef, QualType &PointeeType) {
+ if (PointeeType.getAddressSpace() == LangAS::Default)
+ PointeeType = SemaRef.Context.getAddrSpaceQualType(PointeeType,
+ LangAS::opencl_generic);
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL) {
@@ -4470,6 +4552,9 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
+ if (SemaRef.getLangOpts().OpenCL)
+ deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
+
QualType Result = TL.getType();
if (PointeeType->getAs<ObjCObjectType>()) {
// A dependent pointer type 'T *' has is being transformed such
@@ -4508,6 +4593,9 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
+ if (SemaRef.getLangOpts().OpenCL)
+ deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != TL.getPointeeLoc().getType()) {
@@ -4537,6 +4625,9 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
+ if (SemaRef.getLangOpts().OpenCL)
+ deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != T->getPointeeTypeAsWritten()) {
@@ -5301,13 +5392,6 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
if (ResultType.isNull())
return QualType();
- // Return type can not be qualified with an address space.
- if (ResultType.getAddressSpace() != LangAS::Default) {
- SemaRef.Diag(TL.getReturnLoc().getBeginLoc(),
- diag::err_attribute_address_function_type);
- return QualType();
- }
-
if (getDerived().TransformFunctionTypeParams(
TL.getBeginLoc(), TL.getParams(),
TL.getTypePtr()->param_type_begin(),
@@ -6160,6 +6244,27 @@ TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB,
return Result;
}
+template <typename Derived>
+QualType
+TreeTransform<Derived>::TransformMacroQualifiedType(TypeLocBuilder &TLB,
+ MacroQualifiedTypeLoc TL) {
+ QualType Inner = getDerived().TransformType(TLB, TL.getInnerLoc());
+ if (Inner.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || Inner != TL.getInnerLoc().getType()) {
+ Result =
+ getDerived().RebuildMacroQualifiedType(Inner, TL.getMacroIdentifier());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ MacroQualifiedTypeLoc NewTL = TLB.push<MacroQualifiedTypeLoc>(Result);
+ NewTL.setExpansionLoc(TL.getExpansionLoc());
+ return Result;
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::TransformDependentNameType(
TypeLocBuilder &TLB, DependentNameTypeLoc TL) {
@@ -6517,12 +6622,13 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
bool IsStmtExpr) {
Sema::CompoundScopeRAII CompoundScope(getSema());
+ const Stmt *ExprResult = S->getStmtExprResult();
bool SubStmtInvalid = false;
bool SubStmtChanged = false;
SmallVector<Stmt*, 8> Statements;
for (auto *B : S->body()) {
- StmtResult Result =
- getDerived().TransformStmt(B, !IsStmtExpr || B != S->body_back());
+ StmtResult Result = getDerived().TransformStmt(
+ B, IsStmtExpr && B == ExprResult ? SDK_StmtExprResult : SDK_Discarded);
if (Result.isInvalid()) {
// Immediately fail if this was a DeclStmt, since it's very
@@ -6585,7 +6691,8 @@ TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
return StmtError();
// Transform the statement following the case
- StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ StmtResult SubStmt =
+ getDerived().TransformStmt(S->getSubStmt());
if (SubStmt.isInvalid())
return StmtError();
@@ -6593,11 +6700,11 @@ TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
return getDerived().RebuildCaseStmtBody(Case.get(), SubStmt.get());
}
-template<typename Derived>
-StmtResult
-TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) {
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) {
// Transform the statement following the default case
- StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ StmtResult SubStmt =
+ getDerived().TransformStmt(S->getSubStmt());
if (SubStmt.isInvalid())
return StmtError();
@@ -6608,8 +6715,8 @@ TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) {
template<typename Derived>
StmtResult
-TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
- StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S, StmtDiscardKind SDK) {
+ StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK);
if (SubStmt.isInvalid())
return StmtError();
@@ -6618,6 +6725,11 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) {
if (!LD)
return StmtError();
+ // If we're transforming "in-place" (we're not creating new local
+ // declarations), assume we're replacing the old label statement
+ // and clear out the reference to it.
+ if (LD == S->getDecl())
+ S->getDecl()->setStmt(nullptr);
// FIXME: Pass the real colon location in.
return getDerived().RebuildLabelStmt(S->getIdentLoc(),
@@ -6643,7 +6755,9 @@ const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) {
}
template <typename Derived>
-StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
+StmtResult
+TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S,
+ StmtDiscardKind SDK) {
bool AttrsChanged = false;
SmallVector<const Attr *, 1> Attrs;
@@ -6654,7 +6768,7 @@ StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
Attrs.push_back(R);
}
- StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+ StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK);
if (SubStmt.isInvalid())
return StmtError();
@@ -6967,6 +7081,16 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
Exprs.push_back(Result.get());
}
+ // Go through the Labels.
+ for (unsigned I = 0, E = S->getNumLabels(); I != E; ++I) {
+ Names.push_back(S->getLabelIdentifier(I));
+
+ ExprResult Result = getDerived().TransformExpr(S->getLabelExpr(I));
+ if (Result.isInvalid())
+ return StmtError();
+ ExprsChanged |= Result.get() != S->getLabelExpr(I);
+ Exprs.push_back(Result.get());
+ }
if (!getDerived().AlwaysRebuild() && !ExprsChanged)
return S;
@@ -6980,7 +7104,8 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
S->isVolatile(), S->getNumOutputs(),
S->getNumInputs(), Names.data(),
Constraints, Exprs, AsmString.get(),
- Clobbers, S->getRParenLoc());
+ Clobbers, S->getNumLabels(),
+ S->getRParenLoc());
}
template<typename Derived>
@@ -7039,7 +7164,7 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
if (!Promise)
return StmtError();
- getDerived().transformedLocalDecl(S->getPromiseDecl(), Promise);
+ getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise});
ScopeInfo->CoroutinePromise = Promise;
// Transform the implicit coroutine statements we built during the initial
@@ -7071,13 +7196,22 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
Builder.ReturnValue = Res.get();
if (S->hasDependentPromiseType()) {
- assert(!Promise->getType()->isDependentType() &&
- "the promise type must no longer be dependent");
- assert(!S->getFallthroughHandler() && !S->getExceptionHandler() &&
- !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() &&
- "these nodes should not have been built yet");
- if (!Builder.buildDependentStatements())
- return StmtError();
+ // PR41909: We may find a generic coroutine lambda definition within a
+ // template function that is being instantiated. In this case, the lambda
+ // will have a dependent promise type, until it is used in an expression
+ // that creates an instantiation with a non-dependent promise type. We
+ // should not assert or build coroutine dependent statements for such a
+ // generic lambda.
+ auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD);
+ if (!MD || !MD->getParent()->isGenericLambda()) {
+ assert(!Promise->getType()->isDependentType() &&
+ "the promise type must no longer be dependent");
+ assert(!S->getFallthroughHandler() && !S->getExceptionHandler() &&
+ !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() &&
+ "these nodes should not have been built yet");
+ if (!Builder.buildDependentStatements())
+ return StmtError();
+ }
} else {
if (auto *OnFallthrough = S->getFallthroughHandler()) {
StmtResult Res = getDerived().TransformStmt(OnFallthrough);
@@ -7359,7 +7493,8 @@ StmtResult
TreeTransform<Derived>::TransformObjCForCollectionStmt(
ObjCForCollectionStmt *S) {
// Transform the element statement.
- StmtResult Element = getDerived().TransformStmt(S->getElement());
+ StmtResult Element =
+ getDerived().TransformStmt(S->getElement(), SDK_NotDiscarded);
if (Element.isInvalid())
return StmtError();
@@ -8325,6 +8460,16 @@ TreeTransform<Derived>::TransformOMPSafelenClause(OMPSafelenClause *C) {
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPAllocatorClause(OMPAllocatorClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getAllocator());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPAllocatorClause(
+ E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPSimdlenClause(OMPSimdlenClause *C) {
ExprResult E = getDerived().TransformExpr(C->getSimdlen());
if (E.isInvalid())
@@ -8797,8 +8942,85 @@ TreeTransform<Derived>::TransformOMPDeviceClause(OMPDeviceClause *C) {
C->getLParenLoc(), C->getEndLoc());
}
+template <typename Derived, class T>
+bool transformOMPMappableExprListClause(
+ TreeTransform<Derived> &TT, OMPMappableExprListClause<T> *C,
+ llvm::SmallVectorImpl<Expr *> &Vars, CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperIdInfo,
+ llvm::SmallVectorImpl<Expr *> &UnresolvedMappers) {
+ // Transform expressions in the list.
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = TT.getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return true;
+ Vars.push_back(EVar.get());
+ }
+ // Transform mapper scope specifier and identifier.
+ NestedNameSpecifierLoc QualifierLoc;
+ if (C->getMapperQualifierLoc()) {
+ QualifierLoc = TT.getDerived().TransformNestedNameSpecifierLoc(
+ C->getMapperQualifierLoc());
+ if (!QualifierLoc)
+ return true;
+ }
+ MapperIdScopeSpec.Adopt(QualifierLoc);
+ MapperIdInfo = C->getMapperIdInfo();
+ if (MapperIdInfo.getName()) {
+ MapperIdInfo = TT.getDerived().TransformDeclarationNameInfo(MapperIdInfo);
+ if (!MapperIdInfo.getName())
+ return true;
+ }
+ // Build a list of all candidate OMPDeclareMapperDecls, which is provided by
+ // the previous user-defined mapper lookup in dependent environment.
+ for (auto *E : C->mapperlists()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(TT.getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedMappers.push_back(UnresolvedLookupExpr::Create(
+ TT.getSema().Context, /*NamingClass=*/nullptr,
+ MapperIdScopeSpec.getWithLocInContext(TT.getSema().Context),
+ MapperIdInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(),
+ Decls.end()));
+ } else {
+ UnresolvedMappers.push_back(nullptr);
+ }
+ }
+ return false;
+}
+
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ llvm::SmallVector<Expr *, 16> Vars;
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperIdInfo;
+ llvm::SmallVector<Expr *, 16> UnresolvedMappers;
+ if (transformOMPMappableExprListClause<Derived, OMPMapClause>(
+ *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers))
+ return nullptr;
+ return getDerived().RebuildOMPMapClause(
+ C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec,
+ MapperIdInfo, C->getMapType(), C->isImplicitMapType(), C->getMapLoc(),
+ C->getColonLoc(), Vars, Locs, UnresolvedMappers);
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPAllocateClause(OMPAllocateClause *C) {
+ Expr *Allocator = C->getAllocator();
+ if (Allocator) {
+ ExprResult AllocatorRes = getDerived().TransformExpr(Allocator);
+ if (AllocatorRes.isInvalid())
+ return nullptr;
+ Allocator = AllocatorRes.get();
+ }
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
for (auto *VE : C->varlists()) {
@@ -8807,10 +9029,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
return nullptr;
Vars.push_back(EVar.get());
}
- return getDerived().RebuildOMPMapClause(
- C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), C->getMapType(),
- C->isImplicitMapType(), C->getMapLoc(), C->getColonLoc(), Vars,
- C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPAllocateClause(
+ Allocator, Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(),
+ C->getEndLoc());
}
template <typename Derived>
@@ -8891,30 +9112,30 @@ TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) {
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPToClause(OMPToClause *C) {
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
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->getBeginLoc(),
- C->getLParenLoc(), C->getEndLoc());
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperIdInfo;
+ llvm::SmallVector<Expr *, 16> UnresolvedMappers;
+ if (transformOMPMappableExprListClause<Derived, OMPToClause>(
+ *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers))
+ return nullptr;
+ return getDerived().RebuildOMPToClause(Vars, MapperIdScopeSpec, MapperIdInfo,
+ Locs, UnresolvedMappers);
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPFromClause(OMPFromClause *C) {
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
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->getBeginLoc(),
- C->getLParenLoc(), C->getEndLoc());
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperIdInfo;
+ llvm::SmallVector<Expr *, 16> UnresolvedMappers;
+ if (transformOMPMappableExprListClause<Derived, OMPFromClause>(
+ *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers))
+ return nullptr;
+ return getDerived().RebuildOMPFromClause(
+ Vars, MapperIdScopeSpec, MapperIdInfo, Locs, UnresolvedMappers);
}
template <typename Derived>
@@ -8928,8 +9149,8 @@ OMPClause *TreeTransform<Derived>::TransformOMPUseDevicePtrClause(
return nullptr;
Vars.push_back(EVar.get());
}
- return getDerived().RebuildOMPUseDevicePtrClause(
- Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPUseDevicePtrClause(Vars, Locs);
}
template <typename Derived>
@@ -8943,8 +9164,8 @@ TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
return nullptr;
Vars.push_back(EVar.get());
}
- return getDerived().RebuildOMPIsDevicePtrClause(
- Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPIsDevicePtrClause(Vars, Locs);
}
//===----------------------------------------------------------------------===//
@@ -9072,10 +9293,10 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
SmallVector<Expr *, 4> AssocExprs;
SmallVector<TypeSourceInfo *, 4> AssocTypes;
- for (unsigned i = 0; i != E->getNumAssocs(); ++i) {
- TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i);
- if (TS) {
- TypeSourceInfo *AssocType = getDerived().TransformType(TS);
+ for (const GenericSelectionExpr::Association &Assoc : E->associations()) {
+ TypeSourceInfo *TSI = Assoc.getTypeSourceInfo();
+ if (TSI) {
+ TypeSourceInfo *AssocType = getDerived().TransformType(TSI);
if (!AssocType)
return ExprError();
AssocTypes.push_back(AssocType);
@@ -9083,7 +9304,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
AssocTypes.push_back(nullptr);
}
- ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i));
+ ExprResult AssocExpr =
+ getDerived().TransformExpr(Assoc.getAssociationExpr());
if (AssocExpr.isInvalid())
return ExprError();
AssocExprs.push_back(AssocExpr.get());
@@ -9974,6 +10196,19 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
return getDerived().TransformCallExpr(E);
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformSourceLocExpr(SourceLocExpr *E) {
+ bool NeedRebuildFunc = E->getIdentKind() == SourceLocExpr::Function &&
+ getSema().CurContext != E->getParentContext();
+
+ if (!getDerived().AlwaysRebuild() && !NeedRebuildFunc)
+ return E;
+
+ return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getBeginLoc(),
+ E->getEndLoc(),
+ getSema().CurContext);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
@@ -10032,6 +10267,22 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformBuiltinBitCastExpr(BuiltinBitCastExpr *BCE) {
+ TypeSourceInfo *TSI =
+ getDerived().TransformType(BCE->getTypeInfoAsWritten());
+ if (!TSI)
+ return ExprError();
+
+ ExprResult Sub = getDerived().TransformExpr(BCE->getSubExpr());
+ if (Sub.isInvalid())
+ return ExprError();
+
+ return getDerived().RebuildBuiltinBitCastExpr(BCE->getBeginLoc(), TSI,
+ Sub.get(), BCE->getEndLoc());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) {
return getDerived().TransformCXXNamedCastExpr(E);
}
@@ -10169,8 +10420,9 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
QualType T = getSema().getCurrentThisType();
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
- // Make sure that we capture 'this'.
- getSema().CheckCXXThisCapture(E->getBeginLoc());
+ // Mark it referenced in the new context regardless.
+ // FIXME: this is a bit instantiation-specific.
+ getSema().MarkThisReferenced(E);
return E;
}
@@ -10200,8 +10452,8 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!Param)
return ExprError();
- if (!getDerived().AlwaysRebuild() &&
- Param == E->getParam())
+ if (!getDerived().AlwaysRebuild() && Param == E->getParam() &&
+ E->getUsedContext() == SemaRef.CurContext)
return E;
return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
@@ -10215,7 +10467,8 @@ TreeTransform<Derived>::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
if (!Field)
return ExprError();
- if (!getDerived().AlwaysRebuild() && Field == E->getField())
+ if (!getDerived().AlwaysRebuild() && Field == E->getField() &&
+ E->getUsedContext() == SemaRef.CurContext)
return E;
return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field);
@@ -10248,9 +10501,16 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return ExprError();
// Transform the size of the array we're allocating (if any).
- ExprResult ArraySize = getDerived().TransformExpr(E->getArraySize());
- if (ArraySize.isInvalid())
- return ExprError();
+ Optional<Expr *> ArraySize;
+ if (Optional<Expr *> OldArraySize = E->getArraySize()) {
+ ExprResult NewArraySize;
+ if (*OldArraySize) {
+ NewArraySize = getDerived().TransformExpr(*OldArraySize);
+ if (NewArraySize.isInvalid())
+ return ExprError();
+ }
+ ArraySize = NewArraySize.get();
+ }
// Transform the placement arguments (if any).
bool ArgumentChanged = false;
@@ -10287,7 +10547,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (!getDerived().AlwaysRebuild() &&
AllocTypeInfo == E->getAllocatedTypeSourceInfo() &&
- ArraySize.get() == E->getArraySize() &&
+ ArraySize == E->getArraySize() &&
NewInit.get() == OldInit &&
OperatorNew == E->getOperatorNew() &&
OperatorDelete == E->getOperatorDelete() &&
@@ -10314,7 +10574,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
}
QualType AllocType = AllocTypeInfo->getType();
- if (!ArraySize.get()) {
+ if (!ArraySize) {
// If no array size was specified, but the new expression was
// instantiated with an array type (e.g., "new T" where T is
// instantiated with "int[4]"), extract the outer bound from the
@@ -10342,7 +10602,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
E->getBeginLoc(), E->isGlobalNew(),
/*FIXME:*/ E->getBeginLoc(), PlacementArgs,
/*FIXME:*/ E->getBeginLoc(), E->getTypeIdParens(), AllocType,
- AllocTypeInfo, ArraySize.get(), E->getDirectInitRange(), NewInit.get());
+ AllocTypeInfo, ArraySize, E->getDirectInitRange(), NewInit.get());
}
template<typename Derived>
@@ -10984,33 +11244,78 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Transform any init-capture expressions before entering the scope of the
// lambda body, because they are not semantically within that scope.
typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
- SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
- InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
- E->explicit_capture_begin());
+ struct TransformedInitCapture {
+ // The location of the ... if the result is retaining a pack expansion.
+ SourceLocation EllipsisLoc;
+ // Zero or more expansions of the init-capture.
+ SmallVector<InitCaptureInfoTy, 4> Expansions;
+ };
+ SmallVector<TransformedInitCapture, 4> InitCaptures;
+ InitCaptures.resize(E->explicit_capture_end() - E->explicit_capture_begin());
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
C != CEnd; ++C) {
if (!E->isInitCapture(C))
continue;
- EnterExpressionEvaluationContext EEEC(
- getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
- ExprResult NewExprInitResult = getDerived().TransformInitializer(
- C->getCapturedVar()->getInit(),
- C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
-
- if (NewExprInitResult.isInvalid())
- return ExprError();
- Expr *NewExprInit = NewExprInitResult.get();
+ TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()];
VarDecl *OldVD = C->getCapturedVar();
- QualType NewInitCaptureType =
- getSema().buildLambdaInitCaptureInitialization(
- C->getLocation(), OldVD->getType()->isReferenceType(),
- OldVD->getIdentifier(),
- C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit);
- NewExprInitResult = NewExprInit;
- InitCaptureExprsAndTypes[C - E->capture_begin()] =
- std::make_pair(NewExprInitResult, NewInitCaptureType);
+
+ auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
+ Optional<unsigned> NumExpansions) {
+ ExprResult NewExprInitResult = getDerived().TransformInitializer(
+ OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit);
+
+ if (NewExprInitResult.isInvalid()) {
+ Result.Expansions.push_back(InitCaptureInfoTy(ExprError(), QualType()));
+ return;
+ }
+ Expr *NewExprInit = NewExprInitResult.get();
+
+ QualType NewInitCaptureType =
+ getSema().buildLambdaInitCaptureInitialization(
+ C->getLocation(), OldVD->getType()->isReferenceType(),
+ EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
+ C->getCapturedVar()->getInitStyle() != VarDecl::CInit,
+ NewExprInit);
+ Result.Expansions.push_back(
+ InitCaptureInfoTy(NewExprInit, NewInitCaptureType));
+ };
+
+ // If this is an init-capture pack, consider expanding the pack now.
+ if (OldVD->isParameterPack()) {
+ PackExpansionTypeLoc ExpansionTL = OldVD->getTypeSourceInfo()
+ ->getTypeLoc()
+ .castAs<PackExpansionTypeLoc>();
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(OldVD->getInit(), Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ Optional<unsigned> OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(
+ ExpansionTL.getEllipsisLoc(),
+ OldVD->getInit()->getSourceRange(), Unexpanded, Expand,
+ RetainExpansion, NumExpansions))
+ return ExprError();
+ if (Expand) {
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+ SubstInitCapture(SourceLocation(), None);
+ }
+ }
+ if (!Expand || RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+ SubstInitCapture(ExpansionTL.getEllipsisLoc(), NumExpansions);
+ Result.EllipsisLoc = ExpansionTL.getEllipsisLoc();
+ }
+ } else {
+ SubstInitCapture(SourceLocation(), None);
+ }
}
// Transform the template parameters, and add them to the current
@@ -11048,19 +11353,25 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
LSI->GLTemplateParameterList = TPL;
// Create the local class that will describe the lambda.
+ CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
NewCallOpTSI,
/*KnownDependent=*/false,
E->getCaptureDefault());
- getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
+ getDerived().transformedLocalDecl(OldClass, {Class});
+
+ Optional<std::pair<unsigned, Decl*>> Mangling;
+ if (getDerived().ReplacingOriginal())
+ Mangling = std::make_pair(OldClass->getLambdaManglingNumber(),
+ OldClass->getLambdaContextDecl());
// Build the call operator.
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
- E->getCallOperator()->isConstexpr());
+ E->getCallOperator()->getConstexprKind(), Mangling);
LSI->CallOperator = NewCallOperator;
@@ -11078,7 +11389,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
- getDerived().transformedLocalDecl(E->getCallOperator(), NewCallOperator);
+ getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
@@ -11096,16 +11407,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
bool Invalid = false;
// Transform captures.
- bool FinishedExplicitCaptures = false;
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
C != CEnd; ++C) {
// When we hit the first implicit capture, tell Sema that we've finished
// the list of explicit captures.
- if (!FinishedExplicitCaptures && C->isImplicit()) {
- getSema().finishLambdaExplicitCaptures(LSI);
- FinishedExplicitCaptures = true;
- }
+ if (C->isImplicit())
+ break;
// Capturing 'this' is trivial.
if (C->capturesThis()) {
@@ -11121,24 +11429,33 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Rebuild init-captures, including the implied field declaration.
if (E->isInitCapture(C)) {
- InitCaptureInfoTy InitExprTypePair =
- InitCaptureExprsAndTypes[C - E->capture_begin()];
- ExprResult Init = InitExprTypePair.first;
- QualType InitQualType = InitExprTypePair.second;
- if (Init.isInvalid() || InitQualType.isNull()) {
- Invalid = true;
- continue;
- }
+ TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
+
VarDecl *OldVD = C->getCapturedVar();
- VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
- OldVD->getLocation(), InitExprTypePair.second, OldVD->getIdentifier(),
- OldVD->getInitStyle(), Init.get());
- if (!NewVD)
- Invalid = true;
- else {
- getDerived().transformedLocalDecl(OldVD, NewVD);
+ llvm::SmallVector<Decl*, 4> NewVDs;
+
+ for (InitCaptureInfoTy &Info : NewC.Expansions) {
+ ExprResult Init = Info.first;
+ QualType InitQualType = Info.second;
+ if (Init.isInvalid() || InitQualType.isNull()) {
+ Invalid = true;
+ break;
+ }
+ VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
+ OldVD->getLocation(), InitQualType, NewC.EllipsisLoc,
+ OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get());
+ if (!NewVD) {
+ Invalid = true;
+ break;
+ }
+ NewVDs.push_back(NewVD);
+ getSema().addInitCapture(LSI, NewVD);
}
- getSema().buildInitCaptureField(LSI, NewVD);
+
+ if (Invalid)
+ break;
+
+ getDerived().transformedLocalDecl(OldVD, NewVDs);
continue;
}
@@ -11205,17 +11522,16 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind,
EllipsisLoc);
}
- if (!FinishedExplicitCaptures)
- getSema().finishLambdaExplicitCaptures(LSI);
+ getSema().finishLambdaExplicitCaptures(LSI);
- // Enter a new evaluation context to insulate the lambda from any
- // cleanups from the enclosing full-expression.
+ // FIXME: Sema's lambda-building mechanism expects us to push an expression
+ // evaluation context even if we're not transforming the function body.
getSema().PushExpressionEvaluationContext(
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// Instantiate the body of the lambda expression.
StmtResult Body =
- Invalid ? StmtError() : getDerived().TransformStmt(E->getBody());
+ Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody());
// ActOnLambda* will pop the function scope for us.
FuncScopeCleanup.disable();
@@ -11240,6 +11556,52 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformLambdaBody(LambdaExpr *E, Stmt *S) {
+ return TransformStmt(S);
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::SkipLambdaBody(LambdaExpr *E, Stmt *S) {
+ // Transform captures.
+ for (LambdaExpr::capture_iterator C = E->capture_begin(),
+ CEnd = E->capture_end();
+ C != CEnd; ++C) {
+ // When we hit the first implicit capture, tell Sema that we've finished
+ // the list of explicit captures.
+ if (!C->isImplicit())
+ continue;
+
+ // Capturing 'this' is trivial.
+ if (C->capturesThis()) {
+ getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(),
+ /*BuildAndDiagnose*/ true, nullptr,
+ C->getCaptureKind() == LCK_StarThis);
+ continue;
+ }
+ // Captured expression will be recaptured during captured variables
+ // rebuilding.
+ if (C->capturesVLAType())
+ continue;
+
+ assert(C->capturesVariable() && "unexpected kind of lambda capture");
+ assert(!E->isInitCapture(C) && "implicit init-capture?");
+
+ // Transform the captured variable.
+ VarDecl *CapturedVar = cast_or_null<VarDecl>(
+ getDerived().TransformDecl(C->getLocation(), C->getCapturedVar()));
+ if (!CapturedVar || CapturedVar->isInvalidDecl())
+ return StmtError();
+
+ // Capture the transformed variable.
+ getSema().tryCaptureVariable(CapturedVar, C->getLocation());
+ }
+
+ return S;
+}
+
+template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *E) {
@@ -11659,7 +12021,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ Optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
+ NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -11688,7 +12051,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
return getDerived().RebuildCXXFoldExpr(
E->getBeginLoc(), LHS.get(), E->getOperator(), E->getEllipsisLoc(),
- RHS.get(), E->getEndLoc());
+ RHS.get(), E->getEndLoc(), NumExpansions);
}
// The transform has determined that we should perform an elementwise
@@ -11709,7 +12072,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
Result = getDerived().RebuildCXXFoldExpr(
E->getBeginLoc(), Out.get(), E->getOperator(), E->getEllipsisLoc(),
- Result.get(), E->getEndLoc());
+ Result.get(), E->getEndLoc(), OrigNumExpansions);
if (Result.isInvalid())
return true;
}
@@ -11726,7 +12089,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
Result = getDerived().RebuildCXXFoldExpr(
E->getBeginLoc(), LeftFold ? Result.get() : Out.get(),
E->getOperator(), E->getEllipsisLoc(),
- LeftFold ? Out.get() : Result.get(), E->getEndLoc());
+ LeftFold ? Out.get() : Result.get(), E->getEndLoc(),
+ OrigNumExpansions);
} else if (Result.isUsable()) {
// We've got down to a single element; build a binary operator.
Result = getDerived().RebuildBinaryOperator(
@@ -11751,7 +12115,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
Result = getDerived().RebuildCXXFoldExpr(
E->getBeginLoc(), Result.get(), E->getOperator(), E->getEllipsisLoc(),
- Out.get(), E->getEndLoc());
+ Out.get(), E->getEndLoc(), OrigNumExpansions);
if (Result.isInvalid())
return true;
}
@@ -12277,8 +12641,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
VarDecl *oldCapture = I.getVariable();
// Ignore parameter packs.
- if (isa<ParmVarDecl>(oldCapture) &&
- cast<ParmVarDecl>(oldCapture)->isParameterPack())
+ if (oldCapture->isParameterPack())
continue;
VarDecl *newCapture =
diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp
index 340b7fae78aa..b451403544ed 100644
--- a/lib/Sema/TypeLocBuilder.cpp
+++ b/lib/Sema/TypeLocBuilder.cpp
@@ -1,9 +1,8 @@
//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 536ea1c07f49..1e6883926a80 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -1,9 +1,8 @@
//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//