summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp38
-rw-r--r--lib/Sema/AttributeList.cpp5
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp28
-rw-r--r--lib/Sema/DeclSpec.cpp14
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp2
-rw-r--r--lib/Sema/Sema.cpp185
-rw-r--r--lib/Sema/SemaAttr.cpp69
-rw-r--r--lib/Sema/SemaCast.cpp19
-rw-r--r--lib/Sema/SemaChecking.cpp1265
-rw-r--r--lib/Sema/SemaCodeComplete.cpp124
-rw-r--r--lib/Sema/SemaCoroutine.cpp51
-rw-r--r--lib/Sema/SemaDecl.cpp709
-rw-r--r--lib/Sema/SemaDeclAttr.cpp407
-rw-r--r--lib/Sema/SemaDeclCXX.cpp777
-rw-r--r--lib/Sema/SemaDeclObjC.cpp212
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp14
-rw-r--r--lib/Sema/SemaExpr.cpp693
-rw-r--r--lib/Sema/SemaExprCXX.cpp124
-rw-r--r--lib/Sema/SemaExprMember.cpp65
-rw-r--r--lib/Sema/SemaExprObjC.cpp49
-rw-r--r--lib/Sema/SemaInit.cpp164
-rw-r--r--lib/Sema/SemaLambda.cpp47
-rw-r--r--lib/Sema/SemaLookup.cpp107
-rw-r--r--lib/Sema/SemaObjCProperty.cpp16
-rw-r--r--lib/Sema/SemaOpenMP.cpp1971
-rw-r--r--lib/Sema/SemaOverload.cpp322
-rw-r--r--lib/Sema/SemaPseudoObject.cpp3
-rw-r--r--lib/Sema/SemaStmt.cpp83
-rw-r--r--lib/Sema/SemaStmtAsm.cpp83
-rw-r--r--lib/Sema/SemaStmtAttr.cpp12
-rw-r--r--lib/Sema/SemaTemplate.cpp144
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp182
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp38
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp110
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp183
-rw-r--r--lib/Sema/SemaType.cpp519
-rw-r--r--lib/Sema/TreeTransform.h155
37 files changed, 6146 insertions, 2843 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index f83baa790b49..0033edf326ac 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -29,7 +29,7 @@
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Basic/SourceLocation.h"
@@ -289,14 +289,14 @@ enum ThrowState {
static bool isThrowCaught(const CXXThrowExpr *Throw,
const CXXCatchStmt *Catch) {
+ const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull();
+ if (!CaughtType)
+ return true;
const Type *ThrowType = nullptr;
if (Throw->getSubExpr())
ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull();
if (!ThrowType)
return false;
- const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull();
- if (!CaughtType)
- return true;
if (ThrowType->isReferenceType())
ThrowType = ThrowType->castAs<ReferenceType>()
->getPointeeType()
@@ -361,8 +361,7 @@ static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) {
SmallVector<CFGBlock *, 16> Stack;
Stack.push_back(&BodyCFG->getEntry());
while (!Stack.empty()) {
- CFGBlock *CurBlock = Stack.back();
- Stack.pop_back();
+ CFGBlock *CurBlock = Stack.pop_back_val();
unsigned ID = CurBlock->getBlockID();
ThrowState CurState = States[ID];
@@ -426,7 +425,7 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
static bool isNoexcept(const FunctionDecl *FD) {
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
- if (FPT->isNothrow(FD->getASTContext()))
+ if (FPT->isNothrow(FD->getASTContext()) || FD->hasAttr<NoThrowAttr>())
return true;
return false;
}
@@ -1276,7 +1275,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
tok::r_square, tok::r_square
};
- bool PreferClangAttr = !PP.getLangOpts().CPlusPlus1z;
+ bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17;
StringRef MacroName;
if (PreferClangAttr)
@@ -1292,16 +1291,15 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
- // Only perform this analysis when using C++11. There is no good workflow
- // for this warning when not using C++11. There is no good way to silence
- // the warning (no attribute is available) unless we are using C++11's support
- // for generalized attributes. Once could use pragmas to silence the warning,
- // but as a general solution that is gross and not in the spirit of this
- // warning.
+ // Only perform this analysis when using [[]] attributes. There is no good
+ // workflow for this warning when not using C++11. There is no good way to
+ // silence the warning (no attribute is available) unless we are using
+ // [[]] attributes. One could use pragmas to silence the warning, but as a
+ // general solution that is gross and not in the spirit of this warning.
//
- // NOTE: This an intermediate solution. There are on-going discussions on
+ // NOTE: This an intermediate solution. There are on-going discussions on
// how to properly support this warning outside of C++11 with an annotation.
- if (!AC.getASTContext().getLangOpts().CPlusPlus11)
+ if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes)
return;
FallthroughMapper FM(S);
@@ -2082,10 +2080,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// time.
DiagnosticsEngine &Diags = S.getDiagnostics();
- // Do not do any analysis for declarations in system headers if we are
- // going to just ignore them.
- if (Diags.getSuppressSystemWarnings() &&
- S.SourceMgr.isInSystemHeader(D->getLocation()))
+ // Do not do any analysis if we are going to just ignore them.
+ if (Diags.getIgnoreAllWarnings() ||
+ (Diags.getSuppressSystemWarnings() &&
+ S.SourceMgr.isInSystemHeader(D->getLocation())))
return;
// For code in dependent contexts, we'll do this at instantiation time.
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 724db456785f..14d334746f1f 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -114,7 +114,8 @@ static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName,
// Normalize the attribute name, __foo__ becomes foo. This is only allowable
// for GNU attributes.
bool IsGNU = SyntaxUsed == AttributeList::AS_GNU ||
- (SyntaxUsed == AttributeList::AS_CXX11 && ScopeName == "gnu");
+ ((SyntaxUsed == AttributeList::AS_CXX11 ||
+ SyntaxUsed == AttributeList::AS_C2x) && ScopeName == "gnu");
if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
AttrName.endswith("__"))
AttrName = AttrName.slice(2, AttrName.size() - 2);
@@ -135,7 +136,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
// Ensure that in the case of C++11 attributes, we look for '::foo' if it is
// unscoped.
- if (ScopeName || SyntaxUsed == AS_CXX11)
+ if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
FullName += "::";
FullName += AttrName;
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index f5b0104462f7..542b65327b7d 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -613,24 +613,20 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
///
/// If the name needs to be constructed as a string, that string will be
/// saved into Saved and the returned StringRef will refer to it.
-static StringRef getOrderedName(const CodeCompletionResult &R,
- std::string &Saved) {
- switch (R.Kind) {
- case CodeCompletionResult::RK_Keyword:
- return R.Keyword;
-
- case CodeCompletionResult::RK_Pattern:
- return R.Pattern->getTypedText();
-
- case CodeCompletionResult::RK_Macro:
- return R.Macro->getName();
-
- case CodeCompletionResult::RK_Declaration:
+StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const {
+ switch (Kind) {
+ case RK_Keyword:
+ return Keyword;
+ case RK_Pattern:
+ return Pattern->getTypedText();
+ case RK_Macro:
+ return Macro->getName();
+ case RK_Declaration:
// Handle declarations below.
break;
}
- DeclarationName Name = R.Declaration->getDeclName();
+ DeclarationName Name = Declaration->getDeclName();
// If the name is a simple identifier (by far the common case), or a
// zero-argument selector, just return a reference to that identifier.
@@ -648,8 +644,8 @@ static StringRef getOrderedName(const CodeCompletionResult &R,
bool clang::operator<(const CodeCompletionResult &X,
const CodeCompletionResult &Y) {
std::string XSaved, YSaved;
- StringRef XStr = getOrderedName(X, XSaved);
- StringRef YStr = getOrderedName(Y, YSaved);
+ StringRef XStr = X.getOrderedName(XSaved);
+ StringRef YStr = Y.getOrderedName(YSaved);
int cmp = XStr.compare_lower(YStr);
if (cmp)
return cmp < 0;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index e4e84fcec954..6fe2dcc9895f 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -336,6 +336,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_decimal32:
case TST_decimal64:
case TST_double:
+ case TST_Float16:
case TST_float128:
case TST_enum:
case TST_error:
@@ -505,6 +506,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
+ case DeclSpec::TST_float16: return "_Float16";
case DeclSpec::TST_float128: return "__float128";
case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool";
case DeclSpec::TST_decimal32: return "_Decimal32";
@@ -967,18 +969,6 @@ bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
-bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
- if (Concept_specified) {
- DiagID = diag::ext_duplicate_declspec;
- PrevSpec = "concept";
- return true;
- }
- Concept_specified = true;
- ConceptLoc = Loc;
- return false;
-}
-
void DeclSpec::SaveWrittenBuiltinSpecs() {
writtenBS.Sign = getTypeSpecSign();
writtenBS.Width = getTypeSpecWidth();
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index b7e343c64718..77ace0cfa579 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -19,8 +19,6 @@ using namespace clang;
///\brief Constructs a new multiplexing external sema source and appends the
/// given element to it.
///
-///\param[in] source - An ExternalSemaSource.
-///
MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1,
ExternalSemaSource &s2){
Sources.push_back(&s1);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index a18f71422fde..4e57e5ef81c6 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -70,6 +70,49 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
PushDeclContext(S, Context.getTranslationUnitDecl());
}
+namespace clang {
+namespace sema {
+
+class SemaPPCallbacks : public PPCallbacks {
+ Sema *S = nullptr;
+ llvm::SmallVector<SourceLocation, 8> IncludeStack;
+
+public:
+ void set(Sema &S) { this->S = &S; }
+
+ void reset() { S = nullptr; }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
+ if (!S)
+ return;
+ switch (Reason) {
+ case EnterFile: {
+ SourceManager &SM = S->getSourceManager();
+ SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc));
+ if (IncludeLoc.isValid()) {
+ IncludeStack.push_back(IncludeLoc);
+ S->DiagnoseNonDefaultPragmaPack(
+ Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc);
+ }
+ break;
+ }
+ case ExitFile:
+ if (!IncludeStack.empty())
+ S->DiagnoseNonDefaultPragmaPack(
+ Sema::PragmaPackDiagnoseKind::ChangedStateAtExit,
+ IncludeStack.pop_back_val());
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+} // end namespace sema
+} // end namespace clang
+
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
: ExternalSource(nullptr), isMultiplexExternalSource(false),
@@ -122,6 +165,12 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Initilization of data sharing attributes stack for OpenMP
InitDataSharingAttributesStack();
+
+ std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
+ llvm::make_unique<sema::SemaPPCallbacks>();
+ SemaPPCallbackHandler = Callbacks.get();
+ PP.addPPCallbacks(std::move(Callbacks));
+ SemaPPCallbackHandler->set(*this);
}
void Sema::addImplicitTypedef(StringRef Name, QualType T) {
@@ -306,6 +355,10 @@ Sema::~Sema() {
// Destroys data sharing attributes stack for OpenMP
DestroyDataSharingAttributesStack();
+ // Detach from the PP callback handler which outlives Sema since it's owned
+ // by the preprocessor.
+ SemaPPCallbackHandler->reset();
+
assert(DelayedTypos.empty() && "Uncorrected typos!");
}
@@ -383,14 +436,26 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
}
void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
- if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer)
- return;
- if (E->getType()->isNullPtrType())
+ if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
+ E->getLocStart()))
return;
// nullptr only exists from C++11 on, so don't warn on its absence earlier.
if (!getLangOpts().CPlusPlus11)
return;
+ if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer)
+ return;
+ if (E->IgnoreParenImpCasts()->getType()->isNullPtrType())
+ return;
+
+ // If it is a macro from system header, and if the macro name is not "NULL",
+ // do not warn.
+ SourceLocation MaybeMacroLoc = E->getLocStart();
+ if (Diags.getSuppressSystemWarnings() &&
+ SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
+ !findMacroSpelling(MaybeMacroLoc, "NULL"))
+ return;
+
Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant)
<< FixItHint::CreateReplacement(E->getSourceRange(), "nullptr");
}
@@ -464,7 +529,7 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean;
case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean;
}
- return CK_Invalid;
+ llvm_unreachable("unknown scalar type kind");
}
/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector.
@@ -529,6 +594,23 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return false;
}
+static bool isFunctionOrVarDeclExternC(NamedDecl *ND) {
+ if (auto *FD = dyn_cast<FunctionDecl>(ND))
+ return FD->isExternC();
+ return cast<VarDecl>(ND)->isExternC();
+}
+
+/// Determine whether ND is an external-linkage function or variable whose
+/// type has no linkage.
+bool Sema::isExternalWithNoLinkageType(ValueDecl *VD) {
+ // Note: it's not quite enough to check whether VD has UniqueExternalLinkage,
+ // because we also want to catch the case where its type has VisibleNoLinkage,
+ // which does not affect the linkage of VD.
+ return getLangOpts().CPlusPlus && VD->hasExternalFormalLinkage() &&
+ !isExternalFormalLinkage(VD->getType()->getLinkage()) &&
+ !isFunctionOrVarDeclExternC(VD);
+}
+
/// Obtains a sorted list of functions and variables that are undefined but
/// ODR-used.
void Sema::getUndefinedButUsed(
@@ -545,17 +627,27 @@ void Sema::getUndefinedButUsed(
if (isa<CXXDeductionGuideDecl>(ND))
continue;
+ if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) {
+ // An exported function will always be emitted when defined, so even if
+ // the function is inline, it doesn't have to be emitted in this TU. An
+ // imported function implies that it has been exported somewhere else.
+ continue;
+ }
+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (FD->isDefined())
continue;
if (FD->isExternallyVisible() &&
+ !isExternalWithNoLinkageType(FD) &&
!FD->getMostRecentDecl()->isInlined())
continue;
} else {
auto *VD = cast<VarDecl>(ND);
if (VD->hasDefinition() != VarDecl::DeclarationOnly)
continue;
- if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline())
+ if (VD->isExternallyVisible() &&
+ !isExternalWithNoLinkageType(VD) &&
+ !VD->getMostRecentDecl()->isInline())
continue;
}
@@ -573,33 +665,43 @@ static void checkUndefinedButUsed(Sema &S) {
S.getUndefinedButUsed(Undefined);
if (Undefined.empty()) return;
- for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
- I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
- NamedDecl *ND = I->first;
-
- if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) {
- // An exported function will always be emitted when defined, so even if
- // the function is inline, it doesn't have to be emitted in this TU. An
- // imported function implies that it has been exported somewhere else.
- continue;
- }
-
- if (!ND->isExternallyVisible()) {
- S.Diag(ND->getLocation(), diag::warn_undefined_internal)
- << isa<VarDecl>(ND) << ND;
- } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
+ for (auto Undef : Undefined) {
+ ValueDecl *VD = cast<ValueDecl>(Undef.first);
+ SourceLocation UseLoc = Undef.second;
+
+ if (S.isExternalWithNoLinkageType(VD)) {
+ // C++ [basic.link]p8:
+ // A type without linkage shall not be used as the type of a variable
+ // or function with external linkage unless
+ // -- the entity has C language linkage
+ // -- the entity is not odr-used or is defined in the same TU
+ //
+ // As an extension, accept this in cases where the type is externally
+ // visible, since the function or variable actually can be defined in
+ // another translation unit in that case.
+ S.Diag(VD->getLocation(), isExternallyVisible(VD->getType()->getLinkage())
+ ? diag::ext_undefined_internal_type
+ : diag::err_undefined_internal_type)
+ << isa<VarDecl>(VD) << VD;
+ } else if (!VD->isExternallyVisible()) {
+ // FIXME: We can promote this to an error. The function or variable can't
+ // be defined anywhere else, so the program must necessarily violate the
+ // one definition rule.
+ S.Diag(VD->getLocation(), diag::warn_undefined_internal)
+ << isa<VarDecl>(VD) << VD;
+ } else if (auto *FD = dyn_cast<FunctionDecl>(VD)) {
(void)FD;
assert(FD->getMostRecentDecl()->isInlined() &&
"used object requires definition but isn't inline or internal?");
// FIXME: This is ill-formed; we should reject.
- S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND;
+ S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD;
} else {
- assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() &&
+ assert(cast<VarDecl>(VD)->getMostRecentDecl()->isInline() &&
"used var requires definition but isn't inline or internal?");
- S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND;
+ S.Diag(VD->getLocation(), diag::err_undefined_inline_var) << VD;
}
- if (I->second.isValid())
- S.Diag(I->second, diag::note_used_here);
+ if (UseLoc.isValid())
+ S.Diag(UseLoc, diag::note_used_here);
}
S.UndefinedButUsed.clear();
@@ -635,7 +737,8 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD,
E = RD->decls_end();
I != E && Complete; ++I) {
if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I))
- Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M));
+ Complete = M->isDefined() || M->isDefaulted() ||
+ (M->isPure() && !isa<CXXDestructorDecl>(M));
else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I))
// If the template function is marked as late template parsed at this
// point, it has not been instantiated and therefore we have not
@@ -713,10 +816,24 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() {
/// declarations.
void Sema::ActOnStartOfTranslationUnit() {
if (getLangOpts().ModulesTS) {
+ 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).
- Context.getTranslationUnitDecl()->setModuleOwnershipKind(
- Decl::ModuleOwnershipKind::ModulePrivate);
+ 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);
}
}
@@ -769,6 +886,7 @@ void Sema::ActOnEndOfTranslationUnit() {
CheckDelayedMemberExceptionSpecs();
}
+ DiagnoseUnterminatedPragmaPack();
DiagnoseUnterminatedPragmaAttribute();
// All delayed member exception specs should be checked or we end up accepting
@@ -825,6 +943,17 @@ void Sema::ActOnEndOfTranslationUnit() {
}
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.back().Module->Kind != Module::ModuleInterfaceUnit) {
+ // FIXME: Make a better guess as to where to put the module declaration.
+ Diag(getSourceManager().getLocForStartOfFile(
+ getSourceManager().getMainFileID()),
+ diag::err_module_declaration_missing);
+ }
+
// If we are building a module, resolve all of the exported declarations
// now.
if (Module *CurrentModule = PP.getCurrentModule()) {
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 8c13ead64457..4ba2a317e1f9 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -61,6 +61,17 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
Alignment * 8));
}
+ if (PackIncludeStack.empty())
+ return;
+ // The #pragma pack affected a record in an included file, so Clang should
+ // warn when that pragma was written in a file that included the included
+ // file.
+ for (auto &PackedInclude : llvm::reverse(PackIncludeStack)) {
+ if (PackedInclude.CurrentPragmaLocation != PackStack.CurrentPragmaLocation)
+ break;
+ if (PackedInclude.HasNonDefaultValue)
+ PackedInclude.ShouldWarnOnInclude = true;
+ }
}
void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
@@ -202,6 +213,61 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
}
+void Sema::DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind,
+ SourceLocation IncludeLoc) {
+ if (Kind == PragmaPackDiagnoseKind::NonDefaultStateAtInclude) {
+ SourceLocation PrevLocation = PackStack.CurrentPragmaLocation;
+ // Warn about non-default alignment at #includes (without redundant
+ // warnings for the same directive in nested includes).
+ // The warning is delayed until the end of the file to avoid warnings
+ // for files that don't have any records that are affected by the modified
+ // alignment.
+ bool HasNonDefaultValue =
+ PackStack.hasValue() &&
+ (PackIncludeStack.empty() ||
+ PackIncludeStack.back().CurrentPragmaLocation != PrevLocation);
+ PackIncludeStack.push_back(
+ {PackStack.CurrentValue,
+ PackStack.hasValue() ? PrevLocation : SourceLocation(),
+ HasNonDefaultValue, /*ShouldWarnOnInclude*/ false});
+ return;
+ }
+
+ assert(Kind == PragmaPackDiagnoseKind::ChangedStateAtExit && "invalid kind");
+ PackIncludeState PrevPackState = PackIncludeStack.pop_back_val();
+ if (PrevPackState.ShouldWarnOnInclude) {
+ // Emit the delayed non-default alignment at #include warning.
+ Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include);
+ Diag(PrevPackState.CurrentPragmaLocation, diag::note_pragma_pack_here);
+ }
+ // Warn about modified alignment after #includes.
+ if (PrevPackState.CurrentValue != PackStack.CurrentValue) {
+ Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include);
+ Diag(PackStack.CurrentPragmaLocation, diag::note_pragma_pack_here);
+ }
+}
+
+void Sema::DiagnoseUnterminatedPragmaPack() {
+ if (PackStack.Stack.empty())
+ return;
+ bool IsInnermost = true;
+ for (const auto &StackSlot : llvm::reverse(PackStack.Stack)) {
+ Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof);
+ // The user might have already reset the alignment, so suggest replacing
+ // the reset with a pop.
+ if (IsInnermost && PackStack.CurrentValue == PackStack.DefaultValue) {
+ DiagnosticBuilder DB = Diag(PackStack.CurrentPragmaLocation,
+ diag::note_pragma_pack_pop_instead_reset);
+ SourceLocation FixItLoc = Lexer::findLocationAfterToken(
+ PackStack.CurrentPragmaLocation, tok::l_paren, SourceMgr, LangOpts,
+ /*SkipTrailing=*/false);
+ if (FixItLoc.isValid())
+ DB << FixItHint::CreateInsertion(FixItLoc, "pop");
+ }
+ IsInnermost = false;
+ }
+}
+
void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
MSStructPragmaOn = (Kind == PMSST_ON);
}
@@ -249,7 +315,8 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
return;
}
if (Action & PSK_Push)
- Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
+ Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation,
+ PragmaLocation);
else if (Action & PSK_Pop) {
if (!StackSlotLabel.empty()) {
// If we've got a label, try to find it and jump there.
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index d603101c3fd9..ad6348685b64 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -2458,24 +2458,17 @@ void CastOperation::CheckCStyleCast() {
// GCC's cast to union extension.
if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) {
RecordDecl *RD = DestRecordTy->getDecl();
- RecordDecl::field_iterator Field, FieldEnd;
- for (Field = RD->field_begin(), FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field) {
- if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) &&
- !Field->isUnnamedBitfield()) {
- Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
- << SrcExpr.get()->getSourceRange();
- break;
- }
- }
- if (Field == FieldEnd) {
+ if (CastExpr::getTargetFieldForToUnionCast(RD, SrcType)) {
+ Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
+ << SrcExpr.get()->getSourceRange();
+ Kind = CK_ToUnion;
+ return;
+ } else {
Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< SrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
- Kind = CK_ToUnion;
- return;
}
// OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type.
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index b2223b755061..94070bb9c9aa 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1,4 +1,4 @@
-//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===//
+//===- SemaChecking.cpp - Extra Semantic Checking -------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,34 +12,88 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/AttrIterator.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
+#include "clang/AST/NSAPI.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/UnresolvedSet.h"
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/OpenCLOptions.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/SyncScope.h"
#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetCXXABI.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/AtomicOrdering.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Locale.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <string>
+#include <tuple>
+#include <utility>
using namespace clang;
using namespace sema;
@@ -98,6 +152,28 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
return false;
}
+static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) {
+ // We need at least one argument.
+ if (TheCall->getNumArgs() < 1) {
+ S.Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return true;
+ }
+
+ // All arguments should be wide string literals.
+ for (Expr *Arg : TheCall->arguments()) {
+ auto *Literal = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
+ if (!Literal || !Literal->isWide()) {
+ S.Diag(Arg->getLocStart(), diag::err_msvc_annotation_wide_str)
+ << Arg->getSourceRange();
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Check that the argument to __builtin_addressof is a glvalue, and set the
/// result type to the corresponding pointer type.
static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
@@ -299,6 +375,41 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) {
return IllegalParams;
}
+static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) {
+ if (!S.getOpenCLOptions().isEnabled("cl_khr_subgroups")) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_requires_extension)
+ << 1 << Call->getDirectCallee() << "cl_khr_subgroups";
+ return true;
+ }
+ return false;
+}
+
+static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 2))
+ return true;
+
+ if (checkOpenCLSubgroupExt(S, TheCall))
+ return true;
+
+ // First argument is an ndrange_t type.
+ Expr *NDRangeArg = TheCall->getArg(0);
+ if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") {
+ S.Diag(NDRangeArg->getLocStart(),
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "'ndrange_t'";
+ return true;
+ }
+
+ Expr *BlockArg = TheCall->getArg(1);
+ if (!isBlockPointer(BlockArg)) {
+ S.Diag(BlockArg->getLocStart(),
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
+ return true;
+ }
+ return checkOpenCLBlockArgs(S, BlockArg);
+}
+
/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the
/// get_kernel_work_group_size
/// and get_kernel_preferred_work_group_size_multiple builtin functions.
@@ -580,7 +691,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) {
// OpenCL v2.0 s6.13.16.2 - The built-in read/write
// functions have two forms.
switch (Call->getNumArgs()) {
- case 2: {
+ case 2:
if (checkOpenCLPipeArg(S, Call))
return true;
// The call with 2 arguments should be
@@ -588,7 +699,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) {
// Check packet type T.
if (checkOpenCLPipePacketType(S, Call, 1))
return true;
- } break;
+ break;
case 4: {
if (checkOpenCLPipeArg(S, Call))
@@ -647,6 +758,11 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) {
return true;
}
+ // Since return type of reserve_read/write_pipe built-in function is
+ // reserve_id_t, which is not defined in the builtin def file , we used int
+ // as return type and need to override the return type of these functions.
+ Call->setType(S.Context.OCLReserveIDTy);
+
return false;
}
@@ -690,6 +806,7 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) {
return false;
}
+
// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions.
// \brief Performs semantic analysis for the to_global/local/private call.
// \param S Reference to the semantic analyzer.
@@ -721,8 +838,11 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID,
case Builtin::BIto_local:
Qual.setAddressSpace(LangAS::opencl_local);
break;
+ case Builtin::BIto_private:
+ Qual.setAddressSpace(LangAS::opencl_private);
+ break;
default:
- Qual.removeAddressSpace();
+ llvm_unreachable("Invalid builtin function");
}
Call->setType(S.Context.getPointerType(S.Context.getQualifiedType(
RT.getUnqualifiedType(), Qual)));
@@ -770,7 +890,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
switch (Context.getTargetInfo().getTriple().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
- if (SemaBuiltinVAStartARM(TheCall))
+ if (SemaBuiltinVAStartARMMicrosoft(TheCall))
return ExprError();
break;
default:
@@ -839,7 +959,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (checkArgCount(*this, TheCall, 1))
return true;
break;
-
case Builtin::BI__builtin_classify_type:
if (checkArgCount(*this, TheCall, 1)) return true;
TheCall->setType(Context.IntTy);
@@ -959,6 +1078,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI##ID: \
return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
#include "clang/Basic/Builtins.def"
+ case Builtin::BI__annotation:
+ if (SemaBuiltinMSVCAnnotation(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_annotation:
if (SemaBuiltinAnnotation(*this, TheCall))
return ExprError();
@@ -1048,22 +1171,26 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BIreserve_write_pipe:
case Builtin::BIwork_group_reserve_read_pipe:
case Builtin::BIwork_group_reserve_write_pipe:
+ if (SemaBuiltinReserveRWPipe(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BIsub_group_reserve_read_pipe:
case Builtin::BIsub_group_reserve_write_pipe:
- if (SemaBuiltinReserveRWPipe(*this, TheCall))
+ if (checkOpenCLSubgroupExt(*this, TheCall) ||
+ SemaBuiltinReserveRWPipe(*this, TheCall))
return ExprError();
- // Since return type of reserve_read/write_pipe built-in function is
- // reserve_id_t, which is not defined in the builtin def file , we used int
- // as return type and need to override the return type of these functions.
- TheCall->setType(Context.OCLReserveIDTy);
break;
case Builtin::BIcommit_read_pipe:
case Builtin::BIcommit_write_pipe:
case Builtin::BIwork_group_commit_read_pipe:
case Builtin::BIwork_group_commit_write_pipe:
+ if (SemaBuiltinCommitRWPipe(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BIsub_group_commit_read_pipe:
case Builtin::BIsub_group_commit_write_pipe:
- if (SemaBuiltinCommitRWPipe(*this, TheCall))
+ if (checkOpenCLSubgroupExt(*this, TheCall) ||
+ SemaBuiltinCommitRWPipe(*this, TheCall))
return ExprError();
break;
case Builtin::BIget_pipe_num_packets:
@@ -1088,11 +1215,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall))
return ExprError();
break;
+ break;
+ case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
+ case Builtin::BIget_kernel_sub_group_count_for_ndrange:
+ if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_os_log_format:
case Builtin::BI__builtin_os_log_format_buffer_size:
- if (SemaBuiltinOSLogFormat(TheCall)) {
+ if (SemaBuiltinOSLogFormat(TheCall))
return ExprError();
- }
break;
}
@@ -1422,21 +1554,26 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
- unsigned i = 0, l = 0, u = 0;
+ // FIXME: VFP Intrinsics should error if VFP not present.
switch (BuiltinID) {
default: return false;
- case ARM::BI__builtin_arm_ssat: i = 1; l = 1; u = 31; break;
- case ARM::BI__builtin_arm_usat: i = 1; u = 31; break;
+ case ARM::BI__builtin_arm_ssat:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 1, 32);
+ case ARM::BI__builtin_arm_usat:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31);
+ case ARM::BI__builtin_arm_ssat16:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16);
+ case ARM::BI__builtin_arm_usat16:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
case ARM::BI__builtin_arm_vcvtr_f:
- case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
+ case ARM::BI__builtin_arm_vcvtr_d:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1);
case ARM::BI__builtin_arm_dmb:
case ARM::BI__builtin_arm_dsb:
case ARM::BI__builtin_arm_isb:
- case ARM::BI__builtin_arm_dbg: l = 0; u = 15; break;
+ case ARM::BI__builtin_arm_dbg:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15);
}
-
- // FIXME: VFP Intrinsics should error if VFP not present.
- return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
@@ -1790,6 +1927,26 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) {
return false;
}
+/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
+/// This checks that the target supports __builtin_cpu_is and
+/// that the string argument is constant and valid.
+static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) {
+ Expr *Arg = TheCall->getArg(0);
+
+ // Check if the argument is a string literal.
+ if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+ return S.Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal)
+ << Arg->getSourceRange();
+
+ // Check the contents of the string.
+ StringRef Feature =
+ cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
+ if (!S.Context.getTargetInfo().validateCpuIs(Feature))
+ return S.Diag(TheCall->getLocStart(), diag::err_invalid_cpu_is)
+ << Arg->getSourceRange();
+ return false;
+}
+
// Check if the rounding mode is legal.
bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
// Indicates if this instruction has rounding control or just SAE.
@@ -2103,6 +2260,9 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (BuiltinID == X86::BI__builtin_cpu_supports)
return SemaBuiltinCpuSupports(*this, TheCall);
+ if (BuiltinID == X86::BI__builtin_cpu_is)
+ return SemaBuiltinCpuIs(*this, TheCall);
+
// If the intrinsic has rounding or SAE make sure its valid.
if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall))
return true;
@@ -2209,7 +2369,10 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
i = 1; l = -128; u = 255;
break;
case X86::BI__builtin_ia32_vcvtps2ph:
+ case X86::BI__builtin_ia32_vcvtps2ph_mask:
case X86::BI__builtin_ia32_vcvtps2ph256:
+ case X86::BI__builtin_ia32_vcvtps2ph256_mask:
+ case X86::BI__builtin_ia32_vcvtps2ph512_mask:
case X86::BI__builtin_ia32_rndscaleps_128_mask:
case X86::BI__builtin_ia32_rndscalepd_128_mask:
case X86::BI__builtin_ia32_rndscaleps_256_mask:
@@ -2402,6 +2565,7 @@ bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
}
return false;
}
+
/// \brief Diagnose use of %s directive in an NSString which is being passed
/// as formatting string to formatting method.
static void
@@ -2595,7 +2759,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
// Type safety checking.
if (FDecl) {
for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>())
- CheckArgumentWithTypeTag(I, Args.data());
+ CheckArgumentWithTypeTag(I, Args, Loc);
}
}
@@ -2734,15 +2898,18 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering;
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
llvm_unreachable("There is no ordering argument for an init");
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__atomic_load:
return OrderingCABI != llvm::AtomicOrderingCABI::release &&
OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
return OrderingCABI != llvm::AtomicOrderingCABI::consume &&
@@ -2759,27 +2926,39 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
- // All these operations take one of the following forms:
+ // All the non-OpenCL operations take one of the following forms.
+ // The OpenCL operations take the __c11 forms with one extra argument for
+ // synchronization scope.
enum {
// C __c11_atomic_init(A *, C)
Init,
+
// C __c11_atomic_load(A *, int)
Load,
+
// void __atomic_load(A *, CP, int)
LoadCopy,
+
// void __atomic_store(A *, CP, int)
Copy,
+
// C __c11_atomic_add(A *, M, int)
Arithmetic,
+
// C __atomic_exchange_n(A *, CP, int)
Xchg,
+
// void __atomic_exchange(A *, C *, CP, int)
GNUXchg,
+
// bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int)
C11CmpXchg,
+
// bool __atomic_compare_exchange(A *, C *, CP, bool, int, int)
GNUCmpXchg
} Form = Init;
+
+ const unsigned NumForm = GNUCmpXchg + 1;
const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 };
const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 };
// where:
@@ -2789,12 +2968,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// M is C if C is an integer, and ptrdiff_t if C is a pointer, and
// the int parameters are for orderings.
+ static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm
+ && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
+ "need to update code for modified forms");
static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
AtomicExpr::AO__atomic_load,
"need to update code for modified C11 atomics");
- bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init &&
- Op <= AtomicExpr::AO__c11_atomic_fetch_xor;
+ bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init &&
+ Op <= AtomicExpr::AO__opencl_atomic_fetch_max;
+ bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init &&
+ Op <= AtomicExpr::AO__c11_atomic_fetch_xor) ||
+ IsOpenCL;
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
Op == AtomicExpr::AO__atomic_store_n ||
Op == AtomicExpr::AO__atomic_exchange_n ||
@@ -2803,10 +2988,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
+ case AtomicExpr::AO__opencl_atomic_init:
Form = Init;
break;
case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__opencl_atomic_load:
case AtomicExpr::AO__atomic_load_n:
Form = Load;
break;
@@ -2816,6 +3003,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__opencl_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
Form = Copy;
@@ -2823,6 +3011,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_add:
+ case AtomicExpr::AO__opencl_atomic_fetch_sub:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_sub:
case AtomicExpr::AO__atomic_add_fetch:
@@ -2832,6 +3024,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__opencl_atomic_fetch_and:
+ case AtomicExpr::AO__opencl_atomic_fetch_or:
+ case AtomicExpr::AO__opencl_atomic_fetch_xor:
case AtomicExpr::AO__atomic_fetch_and:
case AtomicExpr::AO__atomic_fetch_or:
case AtomicExpr::AO__atomic_fetch_xor:
@@ -2844,6 +3039,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__opencl_atomic_exchange:
case AtomicExpr::AO__atomic_exchange_n:
Form = Xchg;
break;
@@ -2854,6 +3050,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
Form = C11CmpXchg;
break;
@@ -2863,16 +3061,19 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
}
+ unsigned AdjustedNumArgs = NumArgs[Form];
+ if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init)
+ ++AdjustedNumArgs;
// Check we have the right number of arguments.
- if (TheCall->getNumArgs() < NumArgs[Form]) {
+ if (TheCall->getNumArgs() < AdjustedNumArgs) {
Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << NumArgs[Form] << TheCall->getNumArgs()
+ << 0 << AdjustedNumArgs << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
- } else if (TheCall->getNumArgs() > NumArgs[Form]) {
- Diag(TheCall->getArg(NumArgs[Form])->getLocStart(),
+ } else if (TheCall->getNumArgs() > AdjustedNumArgs) {
+ Diag(TheCall->getArg(AdjustedNumArgs)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 << NumArgs[Form] << TheCall->getNumArgs()
+ << 0 << AdjustedNumArgs << TheCall->getNumArgs()
<< TheCall->getCallee()->getSourceRange();
return ExprError();
}
@@ -2900,9 +3101,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
- if (AtomTy.isConstQualified()) {
+ if (AtomTy.isConstQualified() ||
+ AtomTy.getAddressSpace() == LangAS::opencl_constant) {
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic)
- << Ptr->getType() << Ptr->getSourceRange();
+ << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType()
+ << Ptr->getSourceRange();
return ExprError();
}
ValType = AtomTy->getAs<AtomicType>()->getValueType();
@@ -2971,7 +3174,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
ValType.removeLocalVolatile();
ValType.removeLocalConst();
QualType ResultType = ValType;
- if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init)
+ if (Form == Copy || Form == LoadCopy || Form == GNUXchg ||
+ Form == Init)
ResultType = Context.VoidTy;
else if (Form == C11CmpXchg || Form == GNUCmpXchg)
ResultType = Context.BoolTy;
@@ -2985,7 +3189,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
- for (unsigned i = 1; i != NumArgs[Form]; ++i) {
+ for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) {
QualType Ty;
if (i < NumVals[Form] + 1) {
switch (i) {
@@ -3006,7 +3210,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// Treat this argument as _Nonnull as we want to show a warning if
// NULL is passed into it.
CheckNonNullArgument(*this, ValArg, DRE->getLocStart());
- unsigned AS = 0;
+ LangAS AS = LangAS::Default;
// Keep address space of non-atomic pointer type.
if (const PointerType *PtrTy =
ValArg->getType()->getAs<PointerType>()) {
@@ -3027,7 +3231,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
break;
}
} else {
- // The order(s) are always converted to int.
+ // The order(s) and scope are always converted to int.
Ty = Context.IntTy;
}
@@ -3088,15 +3292,30 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
<< SubExprs[1]->getSourceRange();
}
+ if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
+ auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1);
+ llvm::APSInt Result(32);
+ if (Scope->isIntegerConstantExpr(Result, Context) &&
+ !ScopeModel->isValid(Result.getZExtValue())) {
+ Diag(Scope->getLocStart(), diag::err_atomic_op_has_invalid_synch_scope)
+ << Scope->getSourceRange();
+ }
+ SubExprs.push_back(Scope);
+ }
+
AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
SubExprs, ResultType, Op,
TheCall->getRParenLoc());
if ((Op == AtomicExpr::AO__c11_atomic_load ||
- (Op == AtomicExpr::AO__c11_atomic_store)) &&
+ Op == AtomicExpr::AO__c11_atomic_store ||
+ Op == AtomicExpr::AO__opencl_atomic_load ||
+ Op == AtomicExpr::AO__opencl_atomic_store ) &&
Context.AtomicUsesUnsupportedLibcall(AE))
- Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) <<
- ((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1);
+ Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib)
+ << ((Op == AtomicExpr::AO__c11_atomic_load ||
+ Op == AtomicExpr::AO__opencl_atomic_load)
+ ? 0 : 1);
return AE;
}
@@ -3631,7 +3850,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
bool IsWindows = TT.isOSWindows();
bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
if (IsX64 || IsAArch64) {
- clang::CallingConv CC = CC_C;
+ CallingConv CC = CC_C;
if (const FunctionDecl *FD = S.getCurFunctionDecl())
CC = FD->getType()->getAs<FunctionType>()->getCallConv();
if (IsMSVAStart) {
@@ -3778,7 +3997,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
return false;
}
-bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
+bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
// void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
// const char *named_addr);
@@ -3797,23 +4016,33 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
if (checkVAStartIsInVariadicFunction(*this, Func))
return true;
- const struct {
- unsigned ArgNo;
- QualType Type;
- } ArgumentTypes[] = {
- { 1, Context.getPointerType(Context.CharTy.withConst()) },
- { 2, Context.getSizeType() },
- };
-
- for (const auto &AT : ArgumentTypes) {
- const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens();
- if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType())
- continue;
- Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible)
- << Arg->getType() << AT.Type << 1 /* different class */
- << 0 /* qualifier difference */ << 3 /* parameter mismatch */
- << AT.ArgNo + 1 << Arg->getType() << AT.Type;
- }
+ // __va_start on Windows does not validate the parameter qualifiers
+
+ const Expr *Arg1 = Call->getArg(1)->IgnoreParens();
+ const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr();
+
+ const Expr *Arg2 = Call->getArg(2)->IgnoreParens();
+ const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr();
+
+ const QualType &ConstCharPtrTy =
+ Context.getPointerType(Context.CharTy.withConst());
+ if (!Arg1Ty->isPointerType() ||
+ Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy)
+ Diag(Arg1->getLocStart(), diag::err_typecheck_convert_incompatible)
+ << Arg1->getType() << ConstCharPtrTy
+ << 1 /* different class */
+ << 0 /* qualifier difference */
+ << 3 /* parameter mismatch */
+ << 2 << Arg1->getType() << ConstCharPtrTy;
+
+ const QualType SizeTy = Context.getSizeType();
+ if (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy)
+ Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible)
+ << Arg2->getType() << SizeTy
+ << 1 /* different class */
+ << 0 /* qualifier difference */
+ << 3 /* parameter mismatch */
+ << 3 << Arg2->getType() << SizeTy;
return false;
}
@@ -4143,9 +4372,9 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) {
<< (unsigned)Context.getCharWidth()
<< Arg->getSourceRange();
- if (Result > INT32_MAX)
+ if (Result > std::numeric_limits<int32_t>::max())
return Diag(TheCall->getLocStart(), diag::err_alignment_too_big)
- << INT32_MAX
+ << std::numeric_limits<int32_t>::max()
<< Arg->getSourceRange();
}
@@ -4410,7 +4639,6 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
if (!ValidString)
return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg)
<< Arg->getSourceRange();
-
} else if (IsAArch64Builtin && Fields.size() == 1) {
// If the register name is one of those that appear in the condition below
// and the special register builtin being used is one of the write builtins,
@@ -4464,13 +4692,15 @@ bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) {
}
namespace {
+
class UncoveredArgHandler {
enum { Unknown = -1, AllCovered = -2 };
- signed FirstUncoveredArg;
+
+ signed FirstUncoveredArg = Unknown;
SmallVector<const Expr *, 4> DiagnosticExprs;
public:
- UncoveredArgHandler() : FirstUncoveredArg(Unknown) { }
+ UncoveredArgHandler() = default;
bool hasUncoveredArg() const {
return (FirstUncoveredArg >= 0);
@@ -4514,7 +4744,8 @@ enum StringLiteralCheckType {
SLCT_UncheckedLiteral,
SLCT_CheckedLiteral
};
-} // end anonymous namespace
+
+} // namespace
static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend,
BinaryOperatorKind BinOpKind,
@@ -4547,7 +4778,8 @@ static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend,
// We add an offset to a pointer here so we should support an offset as big as
// possible.
if (Ov) {
- assert(BitWidth <= UINT_MAX / 2 && "index (intermediate) result too big");
+ assert(BitWidth <= std::numeric_limits<unsigned>::max() / 2 &&
+ "index (intermediate) result too big");
Offset = Offset.sext(2 * BitWidth);
sumOffsets(Offset, Addend, BinOpKind, AddendIsRight);
return;
@@ -4557,6 +4789,7 @@ static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend,
}
namespace {
+
// This is a wrapper class around StringLiteral to support offsetted string
// literals as format strings. It takes the offset into account when returning
// the string and its length or the source locations to display notes correctly.
@@ -4575,6 +4808,7 @@ class FormatStringLiteral {
unsigned getByteLength() const {
return FExpr->getByteLength() - getCharByteWidth() * Offset;
}
+
unsigned getLength() const { return FExpr->getLength() - Offset; }
unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); }
@@ -4600,9 +4834,11 @@ class FormatStringLiteral {
SourceLocation getLocStart() const LLVM_READONLY {
return FExpr->getLocStart().getLocWithOffset(Offset);
}
+
SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); }
};
-} // end anonymous namespace
+
+} // namespace
static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
const Expr *OrigFormatExpr,
@@ -4689,10 +4925,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return (CheckLeft && Left < Right) ? Left : Right;
}
- case Stmt::ImplicitCastExprClass: {
+ case Stmt::ImplicitCastExprClass:
E = cast<ImplicitCastExpr>(E)->getSubExpr();
goto tryAgain;
- }
case Stmt::OpaqueValueExprClass:
if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
@@ -4881,7 +5116,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
case Stmt::UnaryOperatorClass: {
const UnaryOperator *UnaOp = cast<UnaryOperator>(E);
auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr());
- if (UnaOp->getOpcode() == clang::UO_AddrOf && ASE) {
+ if (UnaOp->getOpcode() == UO_AddrOf && ASE) {
llvm::APSInt IndexResult;
if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) {
sumOffsets(Offset, IndexResult, BO_Add, /*RHS is int*/ true);
@@ -5014,6 +5249,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
}
namespace {
+
class CheckFormatHandler : public analyze_format_string::FormatStringHandler {
protected:
Sema &S;
@@ -5027,8 +5263,8 @@ protected:
ArrayRef<const Expr *> Args;
unsigned FormatIdx;
llvm::SmallBitVector CoveredArgs;
- bool usesPositionalArgs;
- bool atFirstArg;
+ bool usesPositionalArgs = false;
+ bool atFirstArg = true;
bool inFunctionCall;
Sema::VariadicCallType CallType;
llvm::SmallBitVector &CheckedVarArgs;
@@ -5046,7 +5282,6 @@ public:
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg),
HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx),
- usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall), CallType(callType),
CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
CoveredArgs.resize(numDataArgs);
@@ -5116,7 +5351,8 @@ protected:
bool IsStringLocation, Range StringRange,
ArrayRef<FixItHint> Fixit = None);
};
-} // end anonymous namespace
+
+} // namespace
SourceRange CheckFormatHandler::getFormatStringRange() {
return OrigFormatExpr->getSourceRange();
@@ -5470,6 +5706,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(
//===--- CHECK: Printf format string checking ------------------------------===//
namespace {
+
class CheckPrintfHandler : public CheckFormatHandler {
public:
CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr,
@@ -5534,7 +5771,8 @@ public:
const char *conversionPosition)
override;
};
-} // end anonymous namespace
+
+} // namespace
bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
@@ -5652,10 +5890,6 @@ void CheckPrintfHandler::HandleIgnoredFlag(
getSpecifierRange(ignoredFlag.getPosition(), 1)));
}
-// void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
-// bool IsStringLocation, Range StringRange,
-// ArrayRef<FixItHint> Fixit = None);
-
void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag,
unsigned flagLen) {
// Warn about an empty flag.
@@ -5722,7 +5956,8 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
/// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't
/// allow the call, or if it would be ambiguous).
bool Sema::hasCStrMethod(const Expr *E) {
- typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
+ using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
+
MethodSet Results =
CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType());
for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
@@ -5737,7 +5972,7 @@ bool Sema::hasCStrMethod(const Expr *E) {
// Returns true when a c_str() conversion method is found.
bool CheckPrintfHandler::checkForCStrMembers(
const analyze_printf::ArgType &AT, const Expr *E) {
- typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
+ using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
MethodSet Results =
CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
@@ -5765,7 +6000,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
const char *startSpecifier,
unsigned specifierLen) {
using namespace analyze_format_string;
- using namespace analyze_printf;
+ using namespace analyze_printf;
+
const PrintfConversionSpecifier &CS = FS.getConversionSpecifier();
if (FS.consumesDataArgument()) {
@@ -6009,9 +6245,9 @@ shouldNotPrintDirectly(const ASTContext &Context,
while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
QualType CastTy = llvm::StringSwitch<QualType>(Name)
- .Case("CFIndex", Context.LongTy)
- .Case("NSInteger", Context.LongTy)
- .Case("NSUInteger", Context.UnsignedLongTy)
+ .Case("CFIndex", Context.getNSIntegerType())
+ .Case("NSInteger", Context.getNSIntegerType())
+ .Case("NSUInteger", Context.getNSUIntegerType())
.Case("SInt32", Context.IntTy)
.Case("UInt32", Context.UnsignedIntTy)
.Default(QualType());
@@ -6063,6 +6299,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const Expr *E) {
using namespace analyze_format_string;
using namespace analyze_printf;
+
// Now type check the data expression that matches the
// format specifier.
const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext());
@@ -6200,7 +6437,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CastFix << ")";
SmallVector<FixItHint,4> Hints;
- if (!AT.matchesType(S.Context, IntendedTy))
+ if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly)
Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) {
@@ -6315,6 +6552,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
//===--- CHECK: Scanf format string checking ------------------------------===//
namespace {
+
class CheckScanfHandler : public CheckFormatHandler {
public:
CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr,
@@ -6341,7 +6579,8 @@ public:
void HandleIncompleteScanList(const char *start, const char *end) override;
};
-} // end anonymous namespace
+
+} // namespace
void CheckScanfHandler::HandleIncompleteScanList(const char *start,
const char *end) {
@@ -6354,7 +6593,6 @@ bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {
-
const analyze_scanf::ScanfConversionSpecifier &CS =
FS.getConversionSpecifier();
@@ -7041,8 +7279,8 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
if (!Size)
return false;
- // if E is binop and op is >, <, >=, <=, ==, &&, ||:
- if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp())
+ // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||:
+ if (!Size->isComparisonOp() && !Size->isLogicalOp())
return false;
SourceRange SizeRange = Size->getSourceRange();
@@ -7096,7 +7334,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T,
static const Expr *getSizeOfExprArg(const Expr *E) {
if (const UnaryExprOrTypeTraitExpr *SizeOf =
dyn_cast<UnaryExprOrTypeTraitExpr>(E))
- if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType())
+ if (SizeOf->getKind() == UETT_SizeOf && !SizeOf->isArgumentType())
return SizeOf->getArgumentExpr()->IgnoreParenImpCasts();
return nullptr;
@@ -7106,7 +7344,7 @@ static const Expr *getSizeOfExprArg(const Expr *E) {
static QualType getSizeOfArgType(const Expr *E) {
if (const UnaryExprOrTypeTraitExpr *SizeOf =
dyn_cast<UnaryExprOrTypeTraitExpr>(E))
- if (SizeOf->getKind() == clang::UETT_SizeOf)
+ if (SizeOf->getKind() == UETT_SizeOf)
return SizeOf->getTypeOfArgument();
return QualType();
@@ -7294,7 +7532,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
Ex = Ex->IgnoreParenCasts();
- for (;;) {
+ while (true) {
const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex);
if (!BO || !BO->isAdditiveOp())
break;
@@ -7512,7 +7750,6 @@ static const Expr *EvalAddr(const Expr *E,
static void
CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc) {
-
const Expr *stackE = nullptr;
SmallVector<const DeclRefExpr *, 8> refVars;
@@ -7997,8 +8234,7 @@ struct IntRange {
bool NonNegative;
IntRange(unsigned Width, bool NonNegative)
- : Width(Width), NonNegative(NonNegative)
- {}
+ : Width(Width), NonNegative(NonNegative) {}
/// Returns the range of the bool type.
static IntRange forBoolType() {
@@ -8022,11 +8258,19 @@ struct IntRange {
if (const AtomicType *AT = dyn_cast<AtomicType>(T))
T = AT->getValueType().getTypePtr();
- // For enum types, use the known bit width of the enumerators.
- if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+ if (!C.getLangOpts().CPlusPlus) {
+ // For enum types in C code, use the underlying datatype.
+ if (const EnumType *ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr();
+ } else if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+ // For enum types in C++, use the known bit width of the enumerators.
EnumDecl *Enum = ET->getDecl();
- if (!Enum->isCompleteDefinition())
- return IntRange(C.getIntWidth(QualType(T, 0)), false);
+ // In C++11, enums can have a fixed underlying type. Use this type to
+ // compute the range.
+ if (Enum->isFixed()) {
+ return IntRange(C.getIntWidth(QualType(T, 0)),
+ !ET->isSignedIntegerOrEnumerationType());
+ }
unsigned NumPositive = Enum->getNumPositiveBits();
unsigned NumNegative = Enum->getNumNegativeBits();
@@ -8080,7 +8324,10 @@ struct IntRange {
}
};
-IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
+} // namespace
+
+static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value,
+ unsigned MaxWidth) {
if (value.isSigned() && value.isNegative())
return IntRange(value.getMinSignedBits(), false);
@@ -8092,8 +8339,8 @@ IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
return IntRange(value.getActiveBits(), true);
}
-IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
- unsigned MaxWidth) {
+static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
+ unsigned MaxWidth) {
if (result.isInt())
return GetValueRange(C, result.getInt(), MaxWidth);
@@ -8121,7 +8368,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
-QualType GetExprType(const Expr *E) {
+static QualType GetExprType(const Expr *E) {
QualType Ty = E->getType();
if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>())
Ty = AtomicRHS->getValueType();
@@ -8132,7 +8379,7 @@ QualType GetExprType(const Expr *E) {
/// range of values it might take.
///
/// \param MaxWidth - the width to which the value will be truncated
-IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
+static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
E = E->IgnoreParens();
// Try a full evaluation first.
@@ -8186,6 +8433,8 @@ IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
+ case BO_Cmp:
+ llvm_unreachable("builtin <=> should have class type");
// Boolean-valued operations are single-bit and positive.
case BO_LAnd:
@@ -8350,16 +8599,16 @@ IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
return IntRange::forValueOfType(C, GetExprType(E));
}
-IntRange GetExprRange(ASTContext &C, const Expr *E) {
+static IntRange GetExprRange(ASTContext &C, const Expr *E) {
return GetExprRange(C, E, C.getIntWidth(GetExprType(E)));
}
/// Checks whether the given value, which currently has the given
/// source semantics, has the same value when coerced through the
/// target semantics.
-bool IsSameFloatAfterCast(const llvm::APFloat &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
+static bool IsSameFloatAfterCast(const llvm::APFloat &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
llvm::APFloat truncated = value;
bool ignored;
@@ -8374,9 +8623,9 @@ bool IsSameFloatAfterCast(const llvm::APFloat &value,
/// target semantics.
///
/// The value might be a vector of floats (or a complex number).
-bool IsSameFloatAfterCast(const APValue &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
+static bool IsSameFloatAfterCast(const APValue &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
if (value.isFloat())
return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
@@ -8392,24 +8641,154 @@ bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
+static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
-bool IsZero(Sema &S, Expr *E) {
+static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
if (const DeclRefExpr *DR =
dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (isa<EnumConstantDecl>(DR->getDecl()))
- return false;
+ return true;
// Suppress cases where the '0' value is expanded from a macro.
if (E->getLocStart().isMacroID())
- return false;
+ return true;
- llvm::APSInt Value;
- return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
+ return false;
}
-bool HasEnumType(Expr *E) {
+static bool isKnownToHaveUnsignedValue(Expr *E) {
+ return E->getType()->isIntegerType() &&
+ (!E->getType()->isSignedIntegerType() ||
+ !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType());
+}
+
+namespace {
+/// The promoted range of values of a type. In general this has the
+/// following structure:
+///
+/// |-----------| . . . |-----------|
+/// ^ ^ ^ ^
+/// Min HoleMin HoleMax Max
+///
+/// ... where there is only a hole if a signed type is promoted to unsigned
+/// (in which case Min and Max are the smallest and largest representable
+/// values).
+struct PromotedRange {
+ // Min, or HoleMax if there is a hole.
+ llvm::APSInt PromotedMin;
+ // Max, or HoleMin if there is a hole.
+ llvm::APSInt PromotedMax;
+
+ PromotedRange(IntRange R, unsigned BitWidth, bool Unsigned) {
+ if (R.Width == 0)
+ PromotedMin = PromotedMax = llvm::APSInt(BitWidth, Unsigned);
+ else if (R.Width >= BitWidth && !Unsigned) {
+ // Promotion made the type *narrower*. This happens when promoting
+ // a < 32-bit unsigned / <= 32-bit signed bit-field to 'signed int'.
+ // Treat all values of 'signed int' as being in range for now.
+ PromotedMin = llvm::APSInt::getMinValue(BitWidth, Unsigned);
+ PromotedMax = llvm::APSInt::getMaxValue(BitWidth, Unsigned);
+ } else {
+ PromotedMin = llvm::APSInt::getMinValue(R.Width, R.NonNegative)
+ .extOrTrunc(BitWidth);
+ PromotedMin.setIsUnsigned(Unsigned);
+
+ PromotedMax = llvm::APSInt::getMaxValue(R.Width, R.NonNegative)
+ .extOrTrunc(BitWidth);
+ PromotedMax.setIsUnsigned(Unsigned);
+ }
+ }
+
+ // Determine whether this range is contiguous (has no hole).
+ bool isContiguous() const { return PromotedMin <= PromotedMax; }
+
+ // Where a constant value is within the range.
+ enum ComparisonResult {
+ LT = 0x1,
+ LE = 0x2,
+ GT = 0x4,
+ GE = 0x8,
+ EQ = 0x10,
+ NE = 0x20,
+ InRangeFlag = 0x40,
+
+ Less = LE | LT | NE,
+ Min = LE | InRangeFlag,
+ InRange = InRangeFlag,
+ Max = GE | InRangeFlag,
+ Greater = GE | GT | NE,
+
+ OnlyValue = LE | GE | EQ | InRangeFlag,
+ InHole = NE
+ };
+
+ ComparisonResult compare(const llvm::APSInt &Value) const {
+ assert(Value.getBitWidth() == PromotedMin.getBitWidth() &&
+ Value.isUnsigned() == PromotedMin.isUnsigned());
+ if (!isContiguous()) {
+ assert(Value.isUnsigned() && "discontiguous range for signed compare");
+ if (Value.isMinValue()) return Min;
+ if (Value.isMaxValue()) return Max;
+ if (Value >= PromotedMin) return InRange;
+ if (Value <= PromotedMax) return InRange;
+ return InHole;
+ }
+
+ switch (llvm::APSInt::compareValues(Value, PromotedMin)) {
+ case -1: return Less;
+ case 0: return PromotedMin == PromotedMax ? OnlyValue : Min;
+ case 1:
+ switch (llvm::APSInt::compareValues(Value, PromotedMax)) {
+ case -1: return InRange;
+ case 0: return Max;
+ case 1: return Greater;
+ }
+ }
+
+ llvm_unreachable("impossible compare result");
+ }
+
+ static llvm::Optional<StringRef>
+ constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
+ if (Op == BO_Cmp) {
+ ComparisonResult LTFlag = LT, GTFlag = GT;
+ if (ConstantOnRHS) std::swap(LTFlag, GTFlag);
+
+ if (R & EQ) return StringRef("'std::strong_ordering::equal'");
+ if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
+ if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
+ return llvm::None;
+ }
+
+ ComparisonResult TrueFlag, FalseFlag;
+ if (Op == BO_EQ) {
+ TrueFlag = EQ;
+ FalseFlag = NE;
+ } else if (Op == BO_NE) {
+ TrueFlag = NE;
+ FalseFlag = EQ;
+ } else {
+ if ((Op == BO_LT || Op == BO_GE) ^ ConstantOnRHS) {
+ TrueFlag = LT;
+ FalseFlag = GE;
+ } else {
+ TrueFlag = GT;
+ FalseFlag = LE;
+ }
+ if (Op == BO_GE || Op == BO_LE)
+ std::swap(TrueFlag, FalseFlag);
+ }
+ if (R & TrueFlag)
+ return StringRef("true");
+ if (R & FalseFlag)
+ return StringRef("false");
+ return llvm::None;
+ }
+};
+}
+
+static bool HasEnumType(Expr *E) {
// Strip off implicit integral promotions.
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() != CK_IntegralCast &&
@@ -8421,40 +8800,42 @@ bool HasEnumType(Expr *E) {
return E->getType()->isEnumeralType();
}
-void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
- // Disable warning in template instantiations.
+static int classifyConstantValue(Expr *Constant) {
+ // The values of this enumeration are used in the diagnostics
+ // diag::warn_out_of_range_compare and diag::warn_tautological_bool_compare.
+ enum ConstantValueKind {
+ Miscellaneous = 0,
+ LiteralTrue,
+ LiteralFalse
+ };
+ if (auto *BL = dyn_cast<CXXBoolLiteralExpr>(Constant))
+ return BL->getValue() ? ConstantValueKind::LiteralTrue
+ : ConstantValueKind::LiteralFalse;
+ return ConstantValueKind::Miscellaneous;
+}
+
+static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
+ Expr *Constant, Expr *Other,
+ const llvm::APSInt &Value,
+ bool RhsConstant) {
if (S.inTemplateInstantiation())
- return;
+ return false;
- BinaryOperatorKind op = E->getOpcode();
- if (E->isValueDependent())
- return;
+ Expr *OriginalOther = Other;
- if (op == BO_LT && IsZero(S, E->getRHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << "< 0" << "false" << HasEnumType(E->getLHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_GE && IsZero(S, E->getRHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << ">= 0" << "true" << HasEnumType(E->getLHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_GT && IsZero(S, E->getLHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
- << "0 >" << "false" << HasEnumType(E->getRHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_LE && IsZero(S, E->getLHS())) {
- S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
- << "0 <=" << "true" << HasEnumType(E->getRHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- }
-}
-
-void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
- Expr *Other, const llvm::APSInt &Value,
- bool RhsConstant) {
- // Disable warning in template instantiations.
- if (S.inTemplateInstantiation())
- return;
+ Constant = Constant->IgnoreParenImpCasts();
+ Other = Other->IgnoreParenImpCasts();
+
+ // Suppress warnings on tautological comparisons between values of the same
+ // enumeration type. There are only two ways we could warn on this:
+ // - If the constant is outside the range of representable values of
+ // the enumeration. In such a case, we should warn about the cast
+ // to enumeration type, not about the comparison.
+ // - If the constant is the maximum / minimum in-range value. For an
+ // enumeratin type, such comparisons can be meaningful and useful.
+ if (Constant->getType()->isEnumeralType() &&
+ S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType()))
+ return false;
// TODO: Investigate using GetExprRange() to get tighter bounds
// on the bit ranges.
@@ -8462,179 +8843,32 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
if (const auto *AT = OtherT->getAs<AtomicType>())
OtherT = AT->getValueType();
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
- unsigned OtherWidth = OtherRange.Width;
-
- bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue();
-
- // 0 values are handled later by CheckTrivialUnsignedComparison().
- if ((Value == 0) && (!OtherIsBooleanType))
- return;
-
- BinaryOperatorKind op = E->getOpcode();
- bool IsTrue = true;
-
- // Used for diagnostic printout.
- enum {
- LiteralConstant = 0,
- CXXBoolLiteralTrue,
- CXXBoolLiteralFalse
- } LiteralOrBoolConstant = LiteralConstant;
-
- if (!OtherIsBooleanType) {
- QualType ConstantT = Constant->getType();
- QualType CommonT = E->getLHS()->getType();
- if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
- return;
- assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) &&
- "comparison with non-integer type");
-
- bool ConstantSigned = ConstantT->isSignedIntegerType();
- bool CommonSigned = CommonT->isSignedIntegerType();
-
- bool EqualityOnly = false;
-
- if (CommonSigned) {
- // The common type is signed, therefore no signed to unsigned conversion.
- if (!OtherRange.NonNegative) {
- // Check that the constant is representable in type OtherT.
- if (ConstantSigned) {
- if (OtherWidth >= Value.getMinSignedBits())
- return;
- } else { // !ConstantSigned
- if (OtherWidth >= Value.getActiveBits() + 1)
- return;
- }
- } else { // !OtherSigned
- // Check that the constant is representable in type OtherT.
- // Negative values are out of range.
- if (ConstantSigned) {
- if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
- return;
- } else { // !ConstantSigned
- if (OtherWidth >= Value.getActiveBits())
- return;
- }
- }
- } else { // !CommonSigned
- if (OtherRange.NonNegative) {
- if (OtherWidth >= Value.getActiveBits())
- return;
- } else { // OtherSigned
- assert(!ConstantSigned &&
- "Two signed types converted to unsigned types.");
- // Check to see if the constant is representable in OtherT.
- if (OtherWidth > Value.getActiveBits())
- return;
- // Check to see if the constant is equivalent to a negative value
- // cast to CommonT.
- if (S.Context.getIntWidth(ConstantT) ==
- S.Context.getIntWidth(CommonT) &&
- Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
- return;
- // The constant value rests between values that OtherT can represent
- // after conversion. Relational comparison still works, but equality
- // comparisons will be tautological.
- EqualityOnly = true;
- }
- }
-
- bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
-
- if (op == BO_EQ || op == BO_NE) {
- IsTrue = op == BO_NE;
- } else if (EqualityOnly) {
- return;
- } else if (RhsConstant) {
- if (op == BO_GT || op == BO_GE)
- IsTrue = !PositiveConstant;
- else // op == BO_LT || op == BO_LE
- IsTrue = PositiveConstant;
- } else {
- if (op == BO_LT || op == BO_LE)
- IsTrue = !PositiveConstant;
- else // op == BO_GT || op == BO_GE
- IsTrue = PositiveConstant;
- }
- } else {
- // Other isKnownToHaveBooleanValue
- enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn };
- enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal };
- enum ConstantSide { Lhs, Rhs, SizeOfConstSides };
-
- static const struct LinkedConditions {
- CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal];
- CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal];
- CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal];
- CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal];
- CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal];
- CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal];
-
- } TruthTable = {
- // Constant on LHS. | Constant on RHS. |
- // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One|
- { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } },
- { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } },
- { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } },
- { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } },
- { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } },
- { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } }
- };
-
- bool ConstantIsBoolLiteral = isa<CXXBoolLiteralExpr>(Constant);
-
- enum ConstantValue ConstVal = Zero;
- if (Value.isUnsigned() || Value.isNonNegative()) {
- if (Value == 0) {
- LiteralOrBoolConstant =
- ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant;
- ConstVal = Zero;
- } else if (Value == 1) {
- LiteralOrBoolConstant =
- ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant;
- ConstVal = One;
- } else {
- LiteralOrBoolConstant = LiteralConstant;
- ConstVal = GT_One;
- }
- } else {
- ConstVal = LT_Zero;
- }
-
- CompareBoolWithConstantResult CmpRes;
-
- switch (op) {
- case BO_LT:
- CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal];
- break;
- case BO_GT:
- CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal];
- break;
- case BO_LE:
- CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal];
- break;
- case BO_GE:
- CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal];
- break;
- case BO_EQ:
- CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal];
- break;
- case BO_NE:
- CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal];
- break;
- default:
- CmpRes = Unkwn;
- break;
- }
+ // 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)
+ OtherRange = IntRange::forBoolType();
+
+ // Determine the promoted range of the other type and see if a comparison of
+ // the constant against that range is tautological.
+ PromotedRange OtherPromotedRange(OtherRange, Value.getBitWidth(),
+ Value.isUnsigned());
+ auto Cmp = OtherPromotedRange.compare(Value);
+ auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant);
+ if (!Result)
+ return false;
- if (CmpRes == AFals) {
- IsTrue = false;
- } else if (CmpRes == ATrue) {
- IsTrue = true;
- } else {
- return;
- }
- }
+ // Suppress the diagnostic for an in-range comparison if the constant comes
+ // from a macro or enumerator. We don't want to diagnose
+ //
+ // some_long_value <= INT_MAX
+ //
+ // when sizeof(int) == sizeof(long).
+ bool InRange = Cmp & PromotedRange::InRangeFlag;
+ if (InRange && IsEnumConstOrFromMacro(S, Constant))
+ return false;
// If this is a comparison to an enum constant, include that
// constant in the diagnostic.
@@ -8642,6 +8876,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant))
ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
+ // Should be enough for uint128 (39 decimal digits)
SmallString<64> PrettySourceValue;
llvm::raw_svector_ostream OS(PrettySourceValue);
if (ED)
@@ -8649,17 +8884,35 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
else
OS << Value;
- S.DiagRuntimeBehavior(
- E->getOperatorLoc(), E,
- S.PDiag(diag::warn_out_of_range_compare)
- << OS.str() << LiteralOrBoolConstant
- << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
+ // 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());
+ } else {
+ unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0)
+ ? (HasEnumType(OriginalOther)
+ ? diag::warn_unsigned_enum_always_true_comparison
+ : diag::warn_unsigned_always_true_comparison)
+ : diag::warn_tautological_constant_compare;
+
+ S.Diag(E->getOperatorLoc(), Diag)
+ << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ }
+
+ return true;
}
/// Analyze the operands of the given comparison. Implements the
/// fallback case from AnalyzeComparison.
-void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
}
@@ -8667,7 +8920,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
/// \brief Implements -Wsign-compare.
///
/// \param E the binary operator to check for warnings
-void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// The type the comparison is being performed in.
QualType T = E->getLHS()->getType();
@@ -8680,39 +8933,45 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
if (E->isValueDependent())
return AnalyzeImpConvsInComparison(S, E);
- Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
- Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
-
- bool IsComparisonConstant = false;
-
- // Check whether an integer constant comparison results in a value
- // of 'true' or 'false'.
+ Expr *LHS = E->getLHS();
+ Expr *RHS = E->getRHS();
+
if (T->isIntegralType(S.Context)) {
llvm::APSInt RHSValue;
- bool IsRHSIntegralLiteral =
- RHS->isIntegerConstantExpr(RHSValue, S.Context);
llvm::APSInt LHSValue;
- bool IsLHSIntegralLiteral =
- LHS->isIntegerConstantExpr(LHSValue, S.Context);
- if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral)
- DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true);
- else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral)
- DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false);
- else
- IsComparisonConstant =
- (IsRHSIntegralLiteral && IsLHSIntegralLiteral);
- } else if (!T->hasUnsignedIntegerRepresentation())
- IsComparisonConstant = E->isIntegerConstantExpr(S.Context);
-
- // We don't do anything special if this isn't an unsigned integral
- // comparison: we're only interested in integral comparisons, and
- // signed comparisons only happen in cases we don't care to warn about.
- //
- // We also don't care about value-dependent expressions or expressions
- // whose result is a constant.
- if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant)
+
+ bool IsRHSIntegralLiteral = RHS->isIntegerConstantExpr(RHSValue, S.Context);
+ bool IsLHSIntegralLiteral = LHS->isIntegerConstantExpr(LHSValue, S.Context);
+
+ // We don't care about expressions whose result is a constant.
+ if (IsRHSIntegralLiteral && IsLHSIntegralLiteral)
+ return AnalyzeImpConvsInComparison(S, E);
+
+ // We only care about expressions where just one side is literal
+ if (IsRHSIntegralLiteral ^ IsLHSIntegralLiteral) {
+ // Is the constant on the RHS or LHS?
+ const bool RhsConstant = IsRHSIntegralLiteral;
+ Expr *Const = RhsConstant ? RHS : LHS;
+ Expr *Other = RhsConstant ? LHS : RHS;
+ const llvm::APSInt &Value = RhsConstant ? RHSValue : LHSValue;
+
+ // Check whether an integer constant comparison results in a value
+ // of 'true' or 'false'.
+ if (CheckTautologicalComparison(S, E, Const, Other, Value, RhsConstant))
+ return AnalyzeImpConvsInComparison(S, E);
+ }
+ }
+
+ if (!T->hasUnsignedIntegerRepresentation()) {
+ // We don't do anything special if this isn't an unsigned integral
+ // comparison: we're only interested in integral comparisons, and
+ // signed comparisons only happen in cases we don't care to warn about.
return AnalyzeImpConvsInComparison(S, E);
-
+ }
+
+ LHS = LHS->IgnoreParenImpCasts();
+ RHS = RHS->IgnoreParenImpCasts();
+
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;
@@ -8725,7 +8984,6 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
signedOperand = RHS;
unsignedOperand = LHS;
} else {
- CheckTrivialUnsignedComparison(S, E);
return AnalyzeImpConvsInComparison(S, E);
}
@@ -8737,11 +8995,9 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
- // If the signed range is non-negative, -Wsign-compare won't fire,
- // but we should still check for comparisons which are always true
- // or false.
+ // If the signed range is non-negative, -Wsign-compare won't fire.
if (signedRange.NonNegative)
- return CheckTrivialUnsignedComparison(S, E);
+ return;
// For (in)equality comparisons, if the unsigned operand is a
// constant which cannot collide with a overflowed signed operand,
@@ -8768,8 +9024,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) {
/// Analyzes an attempt to assign the given value to a bitfield.
///
/// Returns true if there was something fishy about the attempt.
-bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
- SourceLocation InitLoc) {
+static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
+ SourceLocation InitLoc) {
assert(Bitfield->isBitField());
if (Bitfield->isInvalidDecl())
return false;
@@ -8899,7 +9155,7 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
/// Analyze the given simple or compound assignment for warning-worthy
/// operations.
-void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
+static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
// Just recurse on the LHS.
AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
@@ -8918,9 +9174,9 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
- SourceLocation CContext, unsigned diag,
- bool pruneControlFlow = false) {
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
+ SourceLocation CContext, unsigned diag,
+ bool pruneControlFlow = false) {
if (pruneControlFlow) {
S.DiagRuntimeBehavior(E->getExprLoc(), E,
S.PDiag(diag)
@@ -8933,16 +9189,16 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
- unsigned diag, bool pruneControlFlow = false) {
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType T,
+ SourceLocation CContext,
+ unsigned diag, bool pruneControlFlow = false) {
DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow);
}
/// Diagnose an implicit cast from a floating point value to an integer value.
-void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
-
- SourceLocation CContext) {
+static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
+ SourceLocation CContext) {
const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool);
const bool PruneWarnings = S.inTemplateInstantiation();
@@ -9032,7 +9288,8 @@ void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
}
}
-std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
+static std::string PrettyPrintInRange(const llvm::APSInt &Value,
+ IntRange Range) {
if (!Range.Width) return "0";
llvm::APSInt ValueInRange = Value;
@@ -9041,7 +9298,7 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
-bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
+static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
if (!isa<ImplicitCastExpr>(Ex))
return false;
@@ -9060,8 +9317,8 @@ bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
FloatCandidateBT && (FloatCandidateBT->isFloatingPoint()));
}
-void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
- SourceLocation CC) {
+static void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
+ SourceLocation CC) {
unsigned NumArgs = TheCall->getNumArgs();
for (unsigned i = 0; i < NumArgs; ++i) {
Expr *CurrA = TheCall->getArg(i);
@@ -9081,7 +9338,8 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
}
}
-void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) {
+static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC) {
if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
E->getExprLoc()))
return;
@@ -9125,20 +9383,24 @@ void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) {
return;
S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
- << (NullKind == Expr::NPCK_CXX11_nullptr) << T << clang::SourceRange(CC)
+ << (NullKind == Expr::NPCK_CXX11_nullptr) << T << SourceRange(CC)
<< FixItHint::CreateReplacement(Loc,
S.getFixItZeroLiteralForType(T, Loc));
}
-void checkObjCArrayLiteral(Sema &S, QualType TargetType,
- ObjCArrayLiteral *ArrayLiteral);
-void checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
- ObjCDictionaryLiteral *DictionaryLiteral);
+static void checkObjCArrayLiteral(Sema &S, QualType TargetType,
+ ObjCArrayLiteral *ArrayLiteral);
+
+static void
+checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
+ ObjCDictionaryLiteral *DictionaryLiteral);
/// Check a single element within a collection literal against the
/// target element type.
-void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType,
- Expr *Element, unsigned ElementKind) {
+static void checkObjCCollectionLiteralElement(Sema &S,
+ QualType TargetElementType,
+ Expr *Element,
+ unsigned ElementKind) {
// Skip a bitcast to 'id' or qualified 'id'.
if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) {
if (ICE->getCastKind() == CK_BitCast &&
@@ -9167,8 +9429,8 @@ void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType,
/// Check an Objective-C array literal being converted to the given
/// target type.
-void checkObjCArrayLiteral(Sema &S, QualType TargetType,
- ObjCArrayLiteral *ArrayLiteral) {
+static void checkObjCArrayLiteral(Sema &S, QualType TargetType,
+ ObjCArrayLiteral *ArrayLiteral) {
if (!S.NSArrayDecl)
return;
@@ -9195,8 +9457,9 @@ void checkObjCArrayLiteral(Sema &S, QualType TargetType,
/// Check an Objective-C dictionary literal being converted to the given
/// target type.
-void checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
- ObjCDictionaryLiteral *DictionaryLiteral) {
+static void
+checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
+ ObjCDictionaryLiteral *DictionaryLiteral) {
if (!S.NSDictionaryDecl)
return;
@@ -9224,8 +9487,8 @@ void checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
// Helper function to filter out cases for constant width constant conversion.
// Don't warn on char array initialization or for non-decimal values.
-bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
- SourceLocation CC) {
+static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC) {
// If initializing from a constant, and the constant starts with '0',
// then it is a binary, octal, or hexadecimal. Allow these constants
// to fill all the bits, even if there is a sign change.
@@ -9248,8 +9511,9 @@ bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
return true;
}
-void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
- SourceLocation CC, bool *ICContext = nullptr) {
+static void
+CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
+ bool *ICContext = nullptr) {
if (E->isTypeDependent() || E->isValueDependent()) return;
const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
@@ -9316,10 +9580,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Strip complex types.
if (isa<ComplexType>(Source)) {
if (!isa<ComplexType>(Target)) {
- if (S.SourceMgr.isInSystemMacro(CC))
+ if (S.SourceMgr.isInSystemMacro(CC) || Target->isBooleanType())
return;
- return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar);
+ return DiagnoseImpCast(S, E, T, CC,
+ S.getLangOpts().CPlusPlus
+ ? diag::err_impcast_complex_scalar
+ : diag::warn_impcast_complex_scalar);
}
Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
@@ -9514,11 +9781,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
-void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
- SourceLocation CC, QualType T);
+static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+ SourceLocation CC, QualType T);
-void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
- SourceLocation CC, bool &ICContext) {
+static void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
+ SourceLocation CC, bool &ICContext) {
E = E->IgnoreParenImpCasts();
if (isa<ConditionalOperator>(E))
@@ -9529,8 +9796,8 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
return CheckImplicitConversion(S, E, T, CC, &ICContext);
}
-void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
- SourceLocation CC, QualType T) {
+static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+ SourceLocation CC, QualType T) {
AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc());
bool Suspicious = false;
@@ -9559,7 +9826,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
/// CheckBoolLikeConversion - Check conversion of given expression to boolean.
/// Input argument E is a logical expression.
-void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
+static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
if (S.getLangOpts().Bool)
return;
CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC);
@@ -9568,7 +9835,8 @@ void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
/// AnalyzeImplicitConversions - Find and report any interesting
/// implicit conversions in the given expression. There are a couple
/// of competing diagnostics here, -Wconversion and -Wsign-compare.
-void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
+static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
+ SourceLocation CC) {
QualType T = OrigE->getType();
Expr *E = OrigE->IgnoreParenImpCasts();
@@ -9661,8 +9929,6 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
::CheckBoolLikeConversion(S, U->getSubExpr(), CC);
}
-} // end anonymous namespace
-
/// Diagnose integer type and any valid implicit convertion to it.
static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) {
// Taking into account implicit conversions,
@@ -9968,10 +10234,11 @@ void Sema::CheckForIntOverflow (Expr *E) {
}
namespace {
+
/// \brief Visitor for expressions which looks for unsequenced operations on the
/// same object.
class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
- typedef EvaluatedExprVisitor<SequenceChecker> Base;
+ using Base = EvaluatedExprVisitor<SequenceChecker>;
/// \brief A tree of sequenced regions within an expression. Two regions are
/// unsequenced if one is an ancestor or a descendent of the other. When we
@@ -9990,11 +10257,14 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
/// \brief A region within an expression which may be sequenced with respect
/// to some other region.
class Seq {
- explicit Seq(unsigned N) : Index(N) {}
- unsigned Index;
friend class SequenceTree;
+
+ unsigned Index = 0;
+
+ explicit Seq(unsigned N) : Index(N) {}
+
public:
- Seq() : Index(0) {}
+ Seq() = default;
};
SequenceTree() { Values.push_back(Value(0)); }
@@ -10038,16 +10308,18 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
};
/// An object for which we can track unsequenced uses.
- typedef NamedDecl *Object;
+ using Object = NamedDecl *;
/// Different flavors of object usage which we track. We only track the
/// least-sequenced usage of each kind.
enum UsageKind {
/// A read of an object. Multiple unsequenced reads are OK.
UK_Use,
+
/// A modification of an object which is sequenced before the value
/// computation of the expression, such as ++n in C++.
UK_ModAsValue,
+
/// A modification of an object which is not sequenced before the value
/// computation of the expression, such as n++.
UK_ModAsSideEffect,
@@ -10056,29 +10328,37 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
};
struct Usage {
- Usage() : Use(nullptr), Seq() {}
- Expr *Use;
+ Expr *Use = nullptr;
SequenceTree::Seq Seq;
+
+ Usage() = default;
};
struct UsageInfo {
- UsageInfo() : Diagnosed(false) {}
Usage Uses[UK_Count];
+
/// Have we issued a diagnostic for this variable already?
- bool Diagnosed;
+ bool Diagnosed = false;
+
+ UsageInfo() = default;
};
- typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap;
+ using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>;
Sema &SemaRef;
+
/// Sequenced regions within the expression.
SequenceTree Tree;
+
/// Declaration modifications and references which we have seen.
UsageInfoMap UsageMap;
+
/// The region we are currently within.
SequenceTree::Seq Region;
+
/// Filled in with declarations which were modified as a side-effect
/// (that is, post-increment operations).
- SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect;
+ SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr;
+
/// Expressions to check later. We defer checking these to reduce
/// stack usage.
SmallVectorImpl<Expr *> &WorkList;
@@ -10093,6 +10373,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
: Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
Self.ModAsSideEffect = &ModAsSideEffect;
}
+
~SequencedSubexpression() {
for (auto &M : llvm::reverse(ModAsSideEffect)) {
UsageInfo &U = Self.UsageMap[M.first];
@@ -10105,7 +10386,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
SequenceChecker &Self;
SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
- SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect;
+ SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect;
};
/// RAII object wrapping the visitation of a subexpression which we might
@@ -10115,9 +10396,10 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
class EvaluationTracker {
public:
EvaluationTracker(SequenceChecker &Self)
- : Self(Self), Prev(Self.EvalTracker), EvalOK(true) {
+ : Self(Self), Prev(Self.EvalTracker) {
Self.EvalTracker = this;
}
+
~EvaluationTracker() {
Self.EvalTracker = Prev;
if (Prev)
@@ -10134,8 +10416,8 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
private:
SequenceChecker &Self;
EvaluationTracker *Prev;
- bool EvalOK;
- } *EvalTracker;
+ bool EvalOK = true;
+ } *EvalTracker = nullptr;
/// \brief Find the object which is produced by the specified expression,
/// if any.
@@ -10169,6 +10451,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
U.Seq = Region;
}
}
+
/// \brief Check whether a modification or use conflicts with a prior usage.
void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind,
bool IsModMod) {
@@ -10196,6 +10479,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
// Uses conflict with other modifications.
checkUsage(O, U, Use, UK_ModAsValue, false);
}
+
void notePostUse(Object O, Expr *Use) {
UsageInfo &U = UsageMap[O];
checkUsage(O, U, Use, UK_ModAsSideEffect, false);
@@ -10208,6 +10492,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
checkUsage(O, U, Mod, UK_ModAsValue, true);
checkUsage(O, U, Mod, UK_Use, false);
}
+
void notePostMod(Object O, Expr *Use, UsageKind UK) {
UsageInfo &U = UsageMap[O];
checkUsage(O, U, Use, UK_ModAsSideEffect, true);
@@ -10216,8 +10501,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
public:
SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList)
- : Base(S.Context), SemaRef(S), Region(Tree.root()),
- ModAsSideEffect(nullptr), WorkList(WorkList), EvalTracker(nullptr) {
+ : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
Visit(E);
}
@@ -10451,7 +10735,8 @@ public:
Tree.merge(Elts[I]);
}
};
-} // end anonymous namespace
+
+} // namespace
void Sema::CheckUnsequencedOperations(Expr *E) {
SmallVector<Expr *, 8> WorkList;
@@ -10868,19 +11153,22 @@ void Sema::CheckArrayAccess(const Expr *expr) {
//===--- CHECK: Objective-C retain cycles ----------------------------------//
namespace {
- struct RetainCycleOwner {
- RetainCycleOwner() : Variable(nullptr), Indirect(false) {}
- VarDecl *Variable;
- SourceRange Range;
- SourceLocation Loc;
- bool Indirect;
- void setLocsFrom(Expr *e) {
- Loc = e->getExprLoc();
- Range = e->getSourceRange();
- }
- };
-} // end anonymous namespace
+struct RetainCycleOwner {
+ VarDecl *Variable = nullptr;
+ SourceRange Range;
+ SourceLocation Loc;
+ bool Indirect = false;
+
+ RetainCycleOwner() = default;
+
+ void setLocsFrom(Expr *e) {
+ Loc = e->getExprLoc();
+ Range = e->getSourceRange();
+ }
+};
+
+} // namespace
/// Consider whether capturing the given variable can possibly lead to
/// a retain cycle.
@@ -10977,15 +11265,16 @@ static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) {
}
namespace {
+
struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
- FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
- : EvaluatedExprVisitor<FindCaptureVisitor>(Context),
- Context(Context), Variable(variable), Capturer(nullptr),
- VarWillBeReased(false) {}
ASTContext &Context;
VarDecl *Variable;
- Expr *Capturer;
- bool VarWillBeReased;
+ Expr *Capturer = nullptr;
+ bool VarWillBeReased = false;
+
+ FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
+ : EvaluatedExprVisitor<FindCaptureVisitor>(Context),
+ Context(Context), Variable(variable) {}
void VisitDeclRefExpr(DeclRefExpr *ref) {
if (ref->getDecl() == Variable && !Capturer)
@@ -11010,6 +11299,7 @@ namespace {
if (OVE->getSourceExpr())
Visit(OVE->getSourceExpr());
}
+
void VisitBinaryOperator(BinaryOperator *BinOp) {
if (!Variable || VarWillBeReased || BinOp->getOpcode() != BO_Assign)
return;
@@ -11026,7 +11316,8 @@ namespace {
}
}
};
-} // end anonymous namespace
+
+} // namespace
/// Check whether the given argument is a block which captures a
/// variable.
@@ -11283,9 +11574,15 @@ void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
}
// Check whether the receiver is captured by any of the arguments.
- for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i)
- if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner))
+ const ObjCMethodDecl *MD = msg->getMethodDecl();
+ for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) {
+ if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) {
+ // noescape blocks should not be retained by the method.
+ if (MD && MD->parameters()[i]->hasAttr<NoEscapeAttr>())
+ continue;
return diagnoseRetainCycle(*this, capturer, owner);
+ }
+ }
}
/// Check a property assign to see if it's likely to cause a retain cycle.
@@ -11433,16 +11730,14 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
//===--- CHECK: Empty statement body (-Wempty-body) ---------------------===//
-namespace {
-bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
- SourceLocation StmtLoc,
- const NullStmt *Body) {
+static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
+ SourceLocation StmtLoc,
+ const NullStmt *Body) {
// Do not warn if the body is a macro that expands to nothing, e.g:
//
// #define CALL(x)
// if (condition)
// CALL(0);
- //
if (Body->hasLeadingEmptyMacro())
return false;
@@ -11465,7 +11760,6 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
return true;
}
-} // end anonymous namespace
void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
const Stmt *Body,
@@ -11577,9 +11871,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
return;
// Check for a call to std::move
- const FunctionDecl *FD = CE->getDirectCallee();
- if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() ||
- !FD->getIdentifier()->isStr("move"))
+ if (!CE->isCallToStdMove())
return;
// Get argument from std::move
@@ -11647,12 +11939,10 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
//===--- Layout compatibility ----------------------------------------------//
-namespace {
-
-bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2);
+static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2);
/// \brief Check if two enumeration types are layout-compatible.
-bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) {
+static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) {
// C++11 [dcl.enum] p8:
// Two enumeration types are layout-compatible if they have the same
// underlying type.
@@ -11661,7 +11951,8 @@ bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) {
}
/// \brief Check if two fields are layout-compatible.
-bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) {
+static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1,
+ FieldDecl *Field2) {
if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
return false;
@@ -11682,9 +11973,8 @@ bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) {
/// \brief Check if two standard-layout structs are layout-compatible.
/// (C++11 [class.mem] p17)
-bool isLayoutCompatibleStruct(ASTContext &C,
- RecordDecl *RD1,
- RecordDecl *RD2) {
+static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1,
+ RecordDecl *RD2) {
// If both records are C++ classes, check that base classes match.
if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) {
// If one of records is a CXXRecordDecl we are in C++ mode,
@@ -11727,9 +12017,8 @@ bool isLayoutCompatibleStruct(ASTContext &C,
/// \brief Check if two standard-layout unions are layout-compatible.
/// (C++11 [class.mem] p18)
-bool isLayoutCompatibleUnion(ASTContext &C,
- RecordDecl *RD1,
- RecordDecl *RD2) {
+static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1,
+ RecordDecl *RD2) {
llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields;
for (auto *Field2 : RD2->fields())
UnmatchedFields.insert(Field2);
@@ -11754,7 +12043,8 @@ bool isLayoutCompatibleUnion(ASTContext &C,
return UnmatchedFields.empty();
}
-bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) {
+static bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1,
+ RecordDecl *RD2) {
if (RD1->isUnion() != RD2->isUnion())
return false;
@@ -11765,7 +12055,7 @@ bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) {
}
/// \brief Check if two types are layout-compatible in C++11 sense.
-bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
+static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
if (T1.isNull() || T2.isNull())
return false;
@@ -11799,11 +12089,9 @@ bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
return false;
}
-} // end anonymous namespace
//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
-namespace {
/// \brief Given a type tag expression find the type tag itself.
///
/// \param TypeExpr Type tag expression, as it appears in user's code.
@@ -11811,8 +12099,8 @@ namespace {
/// \param VD Declaration of an identifier that appears in a type tag.
///
/// \param MagicValue Type tag magic value.
-bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
- const ValueDecl **VD, uint64_t *MagicValue) {
+static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
+ const ValueDecl **VD, uint64_t *MagicValue) {
while(true) {
if (!TypeExpr)
return false;
@@ -11887,7 +12175,7 @@ bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
/// \param TypeInfo Information about the corresponding C type.
///
/// \returns true if the corresponding C type was found.
-bool GetMatchingCType(
+static bool GetMatchingCType(
const IdentifierInfo *ArgumentKind,
const Expr *TypeExpr, const ASTContext &Ctx,
const llvm::DenseMap<Sema::TypeTagMagicValue,
@@ -11930,7 +12218,6 @@ bool GetMatchingCType(
TypeInfo = I->second;
return true;
}
-} // end anonymous namespace
void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
uint64_t MagicValue, QualType Type,
@@ -11945,8 +12232,7 @@ void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
TypeTagData(Type, LayoutCompatible, MustBeNull);
}
-namespace {
-bool IsSameCharType(QualType T1, QualType T2) {
+static bool IsSameCharType(QualType T1, QualType T2) {
const BuiltinType *BT1 = T1->getAs<BuiltinType>();
if (!BT1)
return false;
@@ -11963,13 +12249,20 @@ bool IsSameCharType(QualType T1, QualType T2) {
(T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
(T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
}
-} // end anonymous namespace
void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
- const Expr * const *ExprArgs) {
+ const ArrayRef<const Expr *> ExprArgs,
+ SourceLocation CallSiteLoc) {
const IdentifierInfo *ArgumentKind = Attr->getArgumentKind();
bool IsPointerAttr = Attr->getIsPointer();
+ // Retrieve the argument representing the 'type_tag'.
+ if (Attr->getTypeTagIdx() >= ExprArgs.size()) {
+ // Add 1 to display the user's specified value.
+ Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
+ << 0 << Attr->getTypeTagIdx() + 1;
+ return;
+ }
const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()];
bool FoundWrongKind;
TypeTagData TypeInfo;
@@ -11983,6 +12276,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
return;
}
+ // Retrieve the argument representing the 'arg_idx'.
+ if (Attr->getArgumentIdx() >= ExprArgs.size()) {
+ // Add 1 to display the user's specified value.
+ Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
+ << 1 << Attr->getArgumentIdx() + 1;
+ return;
+ }
const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()];
if (IsPointerAttr) {
// Skip implicit cast of pointer to `void *' (as a function argument).
@@ -12074,8 +12374,9 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
MisalignedMember(Op));
if (MA != MisalignedMembers.end() &&
(T->isIntegerType() ||
- (T->isPointerType() &&
- Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment)))
+ (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
+ Context.getTypeAlignInChars(
+ T->getPointeeType()) <= MA->Alignment))))
MisalignedMembers.erase(MA);
}
}
@@ -12192,8 +12493,8 @@ void Sema::RefersToMemberWithReducedAlignment(
void Sema::CheckAddressOfPackedMember(Expr *rhs) {
using namespace std::placeholders;
+
RefersToMemberWithReducedAlignment(
rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1,
_2, _3, _4));
}
-
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 4de7d422072d..834e149d1af4 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -10,10 +10,11 @@
// This file defines the code-completion semantic actions.
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/QualTypeNames.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
@@ -23,6 +24,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -46,7 +48,7 @@ namespace {
/// the result set (when it returns true) and which declarations should be
/// filtered out (returns false).
typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const;
-
+
typedef CodeCompletionResult Result;
private:
@@ -741,8 +743,18 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {
}
const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
+ if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) {
+ // Explicit destructor calls are very rare.
+ if (isa<CXXDestructorDecl>(ND))
+ return CCP_Unlikely;
+ // Explicit operator and conversion function calls are also very rare.
+ auto DeclNameKind = ND->getDeclName().getNameKind();
+ if (DeclNameKind == DeclarationName::CXXOperatorName ||
+ DeclNameKind == DeclarationName::CXXLiteralOperatorName ||
+ DeclNameKind == DeclarationName::CXXConversionFunctionName)
+ return CCP_Unlikely;
return CCP_MemberDeclaration;
+ }
// Content-based decisions.
if (isa<EnumConstantDecl>(ND))
@@ -1070,9 +1082,16 @@ bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const {
/// ordinary name lookup but is not a type name.
bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
+ if (isa<TypeDecl>(ND))
return false;
-
+ // Objective-C interfaces names are not filtered by this method because they
+ // can be used in a class property expression. We can still filter out
+ // @class declarations though.
+ if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
+ if (!ID->getDefinition())
+ return false;
+ }
+
unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern;
if (SemaRef.getLangOpts().CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member;
@@ -1484,6 +1503,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context,
Policy.AnonymousTagLocations = false;
Policy.SuppressStrongLifetime = true;
Policy.SuppressUnwrittenScope = true;
+ Policy.SuppressScope = true;
return Policy;
}
@@ -1647,21 +1667,23 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
if (CCC == Sema::PCC_Class) {
AddTypedefResult(Results);
+ bool IsNotInheritanceScope =
+ !(S->getFlags() & Scope::ClassInheritanceScope);
// public:
Builder.AddTypedTextChunk("public");
- if (Results.includeCodePatterns())
+ if (IsNotInheritanceScope && Results.includeCodePatterns())
Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
// protected:
Builder.AddTypedTextChunk("protected");
- if (Results.includeCodePatterns())
+ if (IsNotInheritanceScope && Results.includeCodePatterns())
Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
// private:
Builder.AddTypedTextChunk("private");
- if (Results.includeCodePatterns())
+ if (IsNotInheritanceScope && Results.includeCodePatterns())
Builder.AddChunk(CodeCompletionString::CK_Colon);
Results.AddResult(Result(Builder.TakeString()));
}
@@ -2126,9 +2148,10 @@ static void AddResultTypeChunk(ASTContext &Context,
T = Method->getSendResultType(BaseType);
else
T = Method->getReturnType();
- } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) {
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
- else if (isa<UnresolvedUsingValueDecl>(ND)) {
+ T = clang::TypeName::getFullyQualifiedType(T, Context);
+ } else if (isa<UnresolvedUsingValueDecl>(ND)) {
/* Do nothing: ignore unresolved using declarations*/
} else if (const ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(ND)) {
if (!BaseType.isNull())
@@ -3355,12 +3378,9 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
return;
PrintingPolicy Policy = getCompletionPrintingPolicy(S);
- for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(),
- MEnd = Method->end_overridden_methods();
- M != MEnd; ++M) {
+ for (const CXXMethodDecl *Overridden : Method->overridden_methods()) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
- const CXXMethodDecl *Overridden = *M;
if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl())
continue;
@@ -4282,13 +4302,17 @@ static void mergeCandidatesWithResults(Sema &SemaRef,
std::stable_sort(
CandidateSet.begin(), CandidateSet.end(),
[&](const OverloadCandidate &X, const OverloadCandidate &Y) {
- return isBetterOverloadCandidate(SemaRef, X, Y, Loc);
+ return isBetterOverloadCandidate(SemaRef, X, Y, Loc,
+ CandidateSet.getKind());
});
// Add the remaining viable overload candidates as code-completion results.
- for (auto &Candidate : CandidateSet)
+ for (auto &Candidate : CandidateSet) {
+ if (Candidate.Function && Candidate.Function->isDeleted())
+ continue;
if (Candidate.Viable)
Results.push_back(ResultCandidate(Candidate.Function));
+ }
}
}
@@ -4379,9 +4403,11 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
ArgExprs.append(Args.begin(), Args.end());
UnresolvedSet<8> Decls;
Decls.append(UME->decls_begin(), UME->decls_end());
+ const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase();
AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs,
/*SuppressUsedConversions=*/false,
- /*PartialOverloading=*/true);
+ /*PartialOverloading=*/true,
+ FirstArgumentIsBase);
} else {
FunctionDecl *FD = nullptr;
if (auto MCE = dyn_cast<MemberExpr>(NakedFn))
@@ -4574,9 +4600,19 @@ void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) {
void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
- if (!SS.getScopeRep() || !CodeCompleter)
+ if (SS.isEmpty() || !CodeCompleter)
return;
+ // We want to keep the scope specifier even if it's invalid (e.g. the scope
+ // "a::b::" is not corresponding to any context/namespace in the AST), since
+ // 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_Name);
+ CC.setCXXScopeSpecifier(SS);
+ HandleCodeCompleteResults(this, CodeCompleter, CC, nullptr, 0);
+ return;
+ }
// Always pretend to enter a context to ensure that a dependent type
// resolves to a dependent record.
DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true);
@@ -4592,7 +4628,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Name);
Results.EnterNewScope();
-
+
// The "template" keyword can follow "::" in the grammar, but only
// put it into the grammar if the nested-name-specifier is dependent.
NestedNameSpecifier *NNS = SS.getScopeRep();
@@ -4606,16 +4642,21 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
// qualified-id completions.
if (!EnteringContext)
MaybeAddOverrideCalls(*this, Ctx, Results);
- Results.ExitScope();
-
- CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
- /*IncludeGlobalScope=*/true,
- /*IncludeDependentBases=*/true);
+ Results.ExitScope();
- HandleCodeCompleteResults(this, CodeCompleter,
- Results.getCompletionContext(),
- Results.data(),Results.size());
+ if (CodeCompleter->includeNamespaceLevelDecls() ||
+ (!Ctx->isNamespace() && !Ctx->isTranslationUnit())) {
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
+ /*IncludeGlobalScope=*/true,
+ /*IncludeDependentBases=*/true);
+ }
+
+ auto CC = Results.getCompletionContext();
+ CC.setCXXScopeSpecifier(SS);
+
+ HandleCodeCompleteResults(this, CodeCompleter, CC, Results.data(),
+ Results.size());
}
void Sema::CodeCompleteUsing(Scope *S) {
@@ -6630,7 +6671,7 @@ typedef llvm::DenseMap<
/// indexed by selector so they can be easily found.
static void FindImplementableMethods(ASTContext &Context,
ObjCContainerDecl *Container,
- bool WantInstanceMethods,
+ Optional<bool> WantInstanceMethods,
QualType ReturnType,
KnownMethodsMap &KnownMethods,
bool InOriginalClass = true) {
@@ -6701,7 +6742,7 @@ static void FindImplementableMethods(ASTContext &Context,
// we want the methods from this container to override any methods
// we've previously seen with the same selector.
for (auto *M : Container->methods()) {
- if (M->isInstanceMethod() == WantInstanceMethods) {
+ if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) {
if (!ReturnType.isNull() &&
!Context.hasSameUnqualifiedType(ReturnType, M->getReturnType()))
continue;
@@ -7373,8 +7414,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
}
}
-void Sema::CodeCompleteObjCMethodDecl(Scope *S,
- bool IsInstanceMethod,
+void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
ParsedType ReturnTy) {
// Determine the return type of the method we're declaring, if
// provided.
@@ -7429,7 +7469,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
ObjCMethodDecl *Method = M->second.getPointer();
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
-
+
+ // Add the '-'/'+' prefix if it wasn't provided yet.
+ if (!IsInstanceMethod) {
+ Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ }
+
// If the result type was not already provided, add it to the
// pattern as (type).
if (ReturnType.isNull()) {
@@ -7531,11 +7577,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
if (IFace)
for (auto *Cat : IFace->visible_categories())
Containers.push_back(Cat);
-
- for (unsigned I = 0, N = Containers.size(); I != N; ++I)
- for (auto *P : Containers[I]->instance_properties())
- AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context,
- KnownSelectors, Results);
+
+ if (IsInstanceMethod) {
+ for (unsigned I = 0, N = Containers.size(); I != N; ++I)
+ for (auto *P : Containers[I]->instance_properties())
+ AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context,
+ KnownSelectors, Results);
+ }
}
Results.ExitScope();
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index dc7d8e4e9cec..e6b640f878c2 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -363,6 +363,32 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
}
+// See if return type is coroutine-handle and if so, invoke builtin coro-resume
+// on its address. This is to enable experimental support for coroutine-handle
+// returning await_suspend that results in a guranteed tail call to the target
+// coroutine.
+static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
+ SourceLocation Loc) {
+ if (RetType->isReferenceType())
+ return nullptr;
+ Type const *T = RetType.getTypePtr();
+ if (!T->isClassType() && !T->isStructureType())
+ return nullptr;
+
+ // FIXME: Add convertability check to coroutine_handle<>. Possibly via
+ // EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment
+ // a private function in SemaExprCXX.cpp
+
+ ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", None);
+ if (AddressExpr.isInvalid())
+ return nullptr;
+
+ Expr *JustAddress = AddressExpr.get();
+ // FIXME: Check that the type of AddressExpr is void*
+ return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
+ JustAddress);
+}
+
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
@@ -412,16 +438,21 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
// - await-suspend is the expression e.await_suspend(h), which shall be
// a prvalue of type void or bool.
QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
- // non-class prvalues always have cv-unqualified types
- QualType AdjRetType = RetType.getUnqualifiedType();
- if (RetType->isReferenceType() ||
- (AdjRetType != S.Context.BoolTy && AdjRetType != S.Context.VoidTy)) {
- S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
- diag::err_await_suspend_invalid_return_type)
- << RetType;
- S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
- << AwaitSuspend->getDirectCallee();
- Calls.IsInvalid = true;
+
+ // Experimental support for coroutine_handle returning await_suspend.
+ if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc))
+ Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;
+ else {
+ // non-class prvalues always have cv-unqualified types
+ if (RetType->isReferenceType() ||
+ (!RetType->isBooleanType() && !RetType->isVoidType())) {
+ S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
+ diag::err_await_suspend_invalid_return_type)
+ << RetType;
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << AwaitSuspend->getDirectCallee();
+ Calls.IsInvalid = true;
+ }
}
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 59c10128f908..ec5ca6973568 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -132,6 +132,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_wchar_t:
case tok::kw_bool:
@@ -280,7 +281,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
IdentifierInfo **CorrectedII) {
// FIXME: Consider allowing this outside C++1z mode as an extension.
bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
- getLangOpts().CPlusPlus1z && !IsCtorOrDtorName &&
+ getLangOpts().CPlusPlus17 && !IsCtorOrDtorName &&
!isClassName && !HasTrailingDot;
// Determine where we will perform name lookup.
@@ -1447,6 +1448,46 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
F.done();
}
+/// We've determined that \p New is a redeclaration of \p Old. Check that they
+/// have compatible owning modules.
+bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
+ // FIXME: The Modules TS is not clear about how friend declarations are
+ // to be treated. It's not meaningful to have different owning modules for
+ // linkage in redeclarations of the same entity, so for now allow the
+ // redeclaration and change the owning modules to match.
+ if (New->getFriendObjectKind() &&
+ Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) {
+ New->setLocalOwningModule(Old->getOwningModule());
+ makeMergedDefinitionVisible(New);
+ return false;
+ }
+
+ Module *NewM = New->getOwningModule();
+ Module *OldM = Old->getOwningModule();
+ 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;
+ 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
+ // other such declarations shall appear in the purview of the same module
+ Diag(New->getLocation(), diag::err_mismatched_owning_module)
+ << New
+ << NewIsModuleInterface
+ << (NewIsModuleInterface ? NewM->getFullModuleName() : "")
+ << OldIsModuleInterface
+ << (OldIsModuleInterface ? OldM->getFullModuleName() : "");
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ New->setInvalidDecl();
+ return true;
+ }
+
+ return false;
+}
+
static bool isUsingDecl(NamedDecl *D) {
return isa<UsingShadowDecl>(D) ||
isa<UnresolvedUsingTypenameDecl>(D) ||
@@ -1682,7 +1723,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
CXXConstructorDecl *CD = Construct->getConstructor();
- if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>())
+ if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>() &&
+ (VD->getInit()->isValueDependent() || !VD->evaluateValue()))
return false;
}
}
@@ -2623,6 +2665,16 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
}
+ // This redeclaration adds a section attribute.
+ if (New->hasAttr<SectionAttr>() && !Old->hasAttr<SectionAttr>()) {
+ if (auto *VD = dyn_cast<VarDecl>(New)) {
+ if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) {
+ Diag(New->getLocation(), diag::warn_attribute_section_on_redeclaration);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+
if (!Old->hasAttrs())
return;
@@ -2951,6 +3003,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
New->dropAttr<InternalLinkageAttr>();
}
+ if (CheckRedeclarationModuleOwnership(New, Old))
+ return true;
+
if (!getLangOpts().CPlusPlus) {
bool OldOvl = Old->hasAttr<OverloadableAttr>();
if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) {
@@ -3526,8 +3581,6 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne && oi != oe; ++ni, ++oi)
mergeParamDeclAttributes(*ni, *oi, *this);
-
- CheckObjCMethodOverride(newMethod, oldMethod);
}
static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) {
@@ -3820,6 +3873,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
+ if (CheckRedeclarationModuleOwnership(New, Old))
+ return;
+
// Variables with external linkage are analyzed in FinalizeDeclaratorGroup.
// FIXME: The test for external storage here seems wrong? We still
@@ -3843,7 +3899,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
}
- // If this redeclaration makes the function inline, we may need to add it to
+ // If this redeclaration makes the variable inline, we may need to add it to
// UndefinedButUsed.
if (!Old->isInline() && New->isInline() && Old->isUsed(false) &&
!Old->getDefinition() && !New->isThisDeclarationADefinition())
@@ -4143,7 +4199,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
if (DS.isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
- << getLangOpts().CPlusPlus1z;
+ << getLangOpts().CPlusPlus17;
if (DS.isConstexprSpecified()) {
// C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations
@@ -4157,14 +4213,6 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
return TagD;
}
- if (DS.isConceptSpecified()) {
- // C++ Concepts TS [dcl.spec.concept]p1: A concept definition refers to
- // either a function concept and its definition or a variable concept and
- // its initializer.
- Diag(DS.getConceptSpecLoc(), diag::err_concept_wrong_decl_kind);
- return TagD;
- }
-
DiagnoseFunctionSpecifiers(DS);
if (DS.isFriendSpecified()) {
@@ -4371,7 +4419,7 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
SourceLocation NameLoc,
bool IsUnion) {
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName,
- Sema::ForRedeclaration);
+ Sema::ForVisibleRedeclaration);
if (!SemaRef.LookupName(R, S)) return false;
// Pick a representative declaration.
@@ -5305,19 +5353,12 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
- if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo))
- // If this is a typedef, we'll end up spewing multiple diagnostics.
- // Just return early; it's safer. If this is a function, let the
- // "constructor cannot have a return type" diagnostic handle it.
- if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- return nullptr;
-
if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
UPPC_DeclarationType))
D.setInvalidType();
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
// See if this is a redefinition of a variable in the same scope.
if (!D.getCXXScopeSpec().isSet()) {
@@ -5343,8 +5384,10 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)
CreateBuiltins = true;
- if (IsLinkageLookup)
+ if (IsLinkageLookup) {
Previous.clear(LookupRedeclarationWithLinkage);
+ Previous.setRedeclarationKind(ForExternalRedeclaration);
+ }
LookupName(Previous, S, CreateBuiltins);
} else { // Something like "int foo::x;"
@@ -5390,12 +5433,17 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
Previous.clear();
}
+ if (!R->isFunctionType() && DiagnoseClassNameShadow(DC, NameInfo))
+ // Forget that the previous declaration is the injected-class-name.
+ Previous.clear();
+
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
- // typedef (C++ [dcl.typedef]p4).
+ // tag type. Note that this applies to functions, function templates, and
+ // variables, but not to typedefs (C++ [dcl.typedef]p4) or variable templates.
if (Previous.isSingleTagDecl() &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ (TemplateParamLists.size() == 0 || R->isFunctionType()))
Previous.clear();
// Check that there are no default arguments other than in the parameters
@@ -5403,23 +5451,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (getLangOpts().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- if (D.getDeclSpec().isConceptSpecified()) {
- // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
- // applied only to the definition of a function template or variable
- // template, declared in namespace scope
- if (!TemplateParamLists.size()) {
- Diag(D.getDeclSpec().getConceptSpecLoc(),
- diag:: err_concept_wrong_decl_kind);
- return nullptr;
- }
-
- if (!DC->getRedeclContext()->isFileContext()) {
- Diag(D.getIdentifierLoc(),
- diag::err_concept_decls_may_only_appear_in_namespace_scope);
- return nullptr;
- }
- }
-
NamedDecl *New;
bool AddToScope = true;
@@ -5634,13 +5665,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
- << getLangOpts().CPlusPlus1z;
+ << getLangOpts().CPlusPlus17;
if (D.getDeclSpec().isConstexprSpecified())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 1;
- if (D.getDeclSpec().isConceptSpecified())
- Diag(D.getDeclSpec().getConceptSpecLoc(),
- diag::err_concept_wrong_decl_kind);
if (D.getName().Kind != UnqualifiedId::IK_Identifier) {
if (D.getName().Kind == UnqualifiedId::IK_DeductionGuideName)
@@ -5919,7 +5947,7 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
NamedDecl *NewDecl,
bool IsSpecialization,
bool IsDefinition) {
- if (OldDecl->isInvalidDecl())
+ if (OldDecl->isInvalidDecl() || NewDecl->isInvalidDecl())
return;
bool IsTemplate = false;
@@ -6025,13 +6053,30 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
NewDecl->dropAttr<DLLImportAttr>();
}
} else if (IsInline && OldImportAttr && !IsMicrosoft) {
- // In MinGW, seeing a function declared inline drops the dllimport attribute.
+ // In MinGW, seeing a function declared inline drops the dllimport
+ // attribute.
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
S.Diag(NewDecl->getLocation(),
diag::warn_dllimport_dropped_from_inline_function)
<< NewDecl << OldImportAttr;
}
+
+ // A specialization of a class template member function is processed here
+ // since it's a redeclaration. If the parent class is dllexport, the
+ // specialization inherits that attribute. This doesn't happen automatically
+ // since the parent class isn't instantiated until later.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDecl)) {
+ if (MD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization &&
+ !NewImportAttr && !NewExportAttr) {
+ if (const DLLExportAttr *ParentExportAttr =
+ MD->getParent()->getAttr<DLLExportAttr>()) {
+ DLLExportAttr *NewAttr = ParentExportAttr->clone(S.Context);
+ NewAttr->setInherited(true);
+ NewDecl->addAttr(NewAttr);
+ }
+ }
+ }
}
/// Given that we are within the definition of the given function,
@@ -6253,7 +6298,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// The event type cannot be used with the __local, __constant and __global
// address space qualifiers.
if (R->isEventT()) {
- if (R.getAddressSpace()) {
+ if (R.getAddressSpace() != LangAS::opencl_private) {
Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
D.setInvalidType();
}
@@ -6289,7 +6334,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// Suppress the warning in system macros, it's used in macros in some
// popular C system headers, such as in glibc's htonl() macro.
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
- getLangOpts().CPlusPlus1z ? diag::ext_register_storage_class
+ getLangOpts().CPlusPlus17 ? diag::ext_register_storage_class
: diag::warn_deprecated_register)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
@@ -6477,49 +6522,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// C++1z [dcl.spec.constexpr]p1:
// A static data member declared with the constexpr specifier is
// implicitly an inline variable.
- if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus1z)
+ if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus17)
NewVD->setImplicitlyInline();
}
-
- if (D.getDeclSpec().isConceptSpecified()) {
- if (VarTemplateDecl *VTD = NewVD->getDescribedVarTemplate())
- VTD->setConcept();
-
- // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not
- // be declared with the thread_local, inline, friend, or constexpr
- // specifiers, [...]
- if (D.getDeclSpec().getThreadStorageClassSpec() == TSCS_thread_local) {
- Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
- diag::err_concept_decl_invalid_specifiers)
- << 0 << 0;
- NewVD->setInvalidDecl(true);
- }
-
- if (D.getDeclSpec().isConstexprSpecified()) {
- Diag(D.getDeclSpec().getConstexprSpecLoc(),
- diag::err_concept_decl_invalid_specifiers)
- << 0 << 3;
- NewVD->setInvalidDecl(true);
- }
-
- // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
- // applied only to the definition of a function template or variable
- // template, declared in namespace scope.
- if (IsVariableTemplateSpecialization) {
- Diag(D.getDeclSpec().getConceptSpecLoc(),
- diag::err_concept_specified_specialization)
- << (IsPartialSpecialization ? 2 : 1);
- }
-
- // C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the
- // following restrictions:
- // - The declared type shall have the type bool.
- if (!Context.hasSameType(NewVD->getType(), Context.BoolTy) &&
- !NewVD->isInvalidDecl()) {
- Diag(D.getIdentifierLoc(), diag::err_variable_concept_bool_decl);
- NewVD->setInvalidDecl(true);
- }
- }
}
if (D.getDeclSpec().isInlineSpecified()) {
@@ -6533,7 +6538,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
} else {
Diag(D.getDeclSpec().getInlineSpecLoc(),
- getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_inline_variable
+ getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_inline_variable
: diag::ext_inline_variable);
NewVD->setInlineSpecified();
}
@@ -6770,25 +6775,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (!IsVariableTemplateSpecialization)
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
- // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...]
- // an explicit specialization (14.8.3) or a partial specialization of a
- // concept definition.
- if (IsVariableTemplateSpecialization &&
- !D.getDeclSpec().isConceptSpecified() && !Previous.empty() &&
- Previous.isSingleResult()) {
- NamedDecl *PreviousDecl = Previous.getFoundDecl();
- if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(PreviousDecl)) {
- if (VarTmpl->isConcept()) {
- Diag(NewVD->getLocation(), diag::err_concept_specialized)
- << 1 /*variable*/
- << (IsPartialSpecialization ? 2 /*partially specialized*/
- : 1 /*explicitly specialized*/);
- Diag(VarTmpl->getLocation(), diag::note_previous_declaration);
- NewVD->setInvalidDecl();
- }
- }
- }
-
if (NewTemplate) {
VarTemplateDecl *PrevVarTemplate =
NewVD->getPreviousDecl()
@@ -7087,7 +7073,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
return;
LookupResult R(*this, D->getDeclName(), D->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
LookupName(R, S);
if (NamedDecl *ShadowedDecl = getShadowedDeclaration(D, R))
CheckShadow(D, ShadowedDecl, R);
@@ -7260,8 +7246,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// This includes arrays of objects with address space qualifiers, but not
// automatic variables that point to other address spaces.
// ISO/IEC TR 18037 S5.1.2
- if (!getLangOpts().OpenCL
- && NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
+ if (!getLangOpts().OpenCL && NewVD->hasLocalStorage() &&
+ T.getAddressSpace() != LangAS::Default) {
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 0;
NewVD->setInvalidDecl();
return;
@@ -7356,7 +7342,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
}
- } else if (T.getAddressSpace() != LangAS::Default) {
+ } else if (T.getAddressSpace() != LangAS::opencl_private) {
// Do not allow other address spaces on automatic variable.
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
NewVD->setInvalidDecl();
@@ -7531,16 +7517,14 @@ enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted };
static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD,
OverrideErrorKind OEK = OEK_All) {
S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods();
- I != E; ++I) {
+ for (const CXXMethodDecl *O : MD->overridden_methods()) {
// This check (& the OEK parameter) could be replaced by a predicate, but
// without lambdas that would be overkill. This is still nicer than writing
// out the diag loop 3 times.
if ((OEK == OEK_All) ||
- (OEK == OEK_NonDeleted && !(*I)->isDeleted()) ||
- (OEK == OEK_Deleted && (*I)->isDeleted()))
- S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+ (OEK == OEK_NonDeleted && !O->isDeleted()) ||
+ (OEK == OEK_Deleted && O->isDeleted()))
+ S.Diag(O->getLocation(), diag::note_overridden_virtual_function);
}
}
@@ -7663,7 +7647,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
IsLocalFriend ? Sema::LookupLocalFriendName
: Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ Sema::ForVisibleRedeclaration);
NewFD->setInvalidDecl();
if (IsLocalFriend)
@@ -7991,7 +7975,8 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PointeeType->isPointerType())
return PtrPtrKernelParam;
if (PointeeType.getAddressSpace() == LangAS::opencl_generic ||
- PointeeType.getAddressSpace() == 0)
+ PointeeType.getAddressSpace() == LangAS::opencl_private ||
+ PointeeType.getAddressSpace() == LangAS::Default)
return InvalidAddrSpacePtrKernelParam;
return PtrKernelParam;
}
@@ -8241,7 +8226,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
- bool isConcept = D.getDeclSpec().isConceptSpecified();
isFriend = D.getDeclSpec().isFriendSpecified();
if (isFriend && !isInline && D.isFunctionDefinition()) {
// C++ [class.friend]p5
@@ -8453,89 +8437,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
}
- if (isConcept) {
- // This is a function concept.
- if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate())
- FTD->setConcept();
-
- // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
- // applied only to the definition of a function template [...]
- if (!D.isFunctionDefinition()) {
- Diag(D.getDeclSpec().getConceptSpecLoc(),
- diag::err_function_concept_not_defined);
- NewFD->setInvalidDecl();
- }
-
- // C++ Concepts TS [dcl.spec.concept]p1: [...] A function concept shall
- // have no exception-specification and is treated as if it were specified
- // with noexcept(true) (15.4). [...]
- if (const FunctionProtoType *FPT = R->getAs<FunctionProtoType>()) {
- if (FPT->hasExceptionSpec()) {
- SourceRange Range;
- if (D.isFunctionDeclarator())
- Range = D.getFunctionTypeInfo().getExceptionSpecRange();
- Diag(NewFD->getLocation(), diag::err_function_concept_exception_spec)
- << FixItHint::CreateRemoval(Range);
- NewFD->setInvalidDecl();
- } else {
- Context.adjustExceptionSpec(NewFD, EST_BasicNoexcept);
- }
-
- // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the
- // following restrictions:
- // - The declared return type shall have the type bool.
- if (!Context.hasSameType(FPT->getReturnType(), Context.BoolTy)) {
- Diag(D.getIdentifierLoc(), diag::err_function_concept_bool_ret);
- NewFD->setInvalidDecl();
- }
-
- // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the
- // following restrictions:
- // - The declaration's parameter list shall be equivalent to an empty
- // parameter list.
- if (FPT->getNumParams() > 0 || FPT->isVariadic())
- Diag(NewFD->getLocation(), diag::err_function_concept_with_params);
- }
-
- // C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is
- // implicity defined to be a constexpr declaration (implicitly inline)
- NewFD->setImplicitlyInline();
-
- // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not
- // be declared with the thread_local, inline, friend, or constexpr
- // specifiers, [...]
- if (isInline) {
- Diag(D.getDeclSpec().getInlineSpecLoc(),
- diag::err_concept_decl_invalid_specifiers)
- << 1 << 1;
- NewFD->setInvalidDecl(true);
- }
-
- if (isFriend) {
- Diag(D.getDeclSpec().getFriendSpecLoc(),
- diag::err_concept_decl_invalid_specifiers)
- << 1 << 2;
- NewFD->setInvalidDecl(true);
- }
-
- if (isConstexpr) {
- Diag(D.getDeclSpec().getConstexprSpecLoc(),
- diag::err_concept_decl_invalid_specifiers)
- << 1 << 3;
- NewFD->setInvalidDecl(true);
- }
-
- // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
- // applied only to the definition of a function template or variable
- // template, declared in namespace scope.
- if (isFunctionTemplateSpecialization) {
- Diag(D.getDeclSpec().getConceptSpecLoc(),
- diag::err_concept_specified_specialization) << 1;
- NewFD->setInvalidDecl(true);
- return NewFD;
- }
- }
-
// If __module_private__ was specified, mark the function accordingly.
if (D.getDeclSpec().isModulePrivateSpecified()) {
if (isFunctionTemplateSpecialization) {
@@ -8760,10 +8661,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
- unsigned AddressSpace = NewFD->getReturnType().getAddressSpace();
- if (AddressSpace == LangAS::opencl_local ||
- AddressSpace == LangAS::opencl_global ||
- AddressSpace == LangAS::opencl_constant) {
+ LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
+ if (AddressSpace != LangAS::Default) {
Diag(NewFD->getLocation(),
diag::err_opencl_return_value_with_address_space);
NewFD->setInvalidDecl();
@@ -8890,10 +8789,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::ext_function_specialization_in_class :
diag::err_function_specialization_in_class)
<< NewFD->getDeclName();
- } else if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs
- : nullptr),
- Previous))
+ } else if (!NewFD->isInvalidDecl() &&
+ CheckFunctionTemplateSpecialization(
+ NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr),
+ Previous))
NewFD->setInvalidDecl();
// C++ [dcl.stc]p1:
@@ -9529,7 +9428,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// return type. (Exception specifications on the function itself are OK in
// most cases, and exception specifications are not permitted in most other
// contexts where they could make it into a mangling.)
- if (!getLangOpts().CPlusPlus1z && !NewFD->getPrimaryTemplate()) {
+ if (!getLangOpts().CPlusPlus17 && !NewFD->getPrimaryTemplate()) {
auto HasNoexcept = [&](QualType T) -> bool {
// Strip off declarator chunks that could be between us and a function
// type. We don't need to look far, exception specifications are very
@@ -9552,7 +9451,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
AnyNoexcept |= HasNoexcept(T);
if (AnyNoexcept)
Diag(NewFD->getLocation(),
- diag::warn_cxx1z_compat_exception_spec_in_signature)
+ diag::warn_cxx17_compat_exception_spec_in_signature)
<< NewFD;
}
@@ -9601,6 +9500,13 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
assert(T->isFunctionType() && "function decl is not of function type");
const FunctionType* FT = T->castAs<FunctionType>();
+ // Set default calling convention for main()
+ if (FT->getCallConv() != CC_C) {
+ FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC_C));
+ FD->setType(QualType(FT, 0));
+ T = Context.getCanonicalType(FD->getType());
+ }
+
if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) {
// In C with GNU extensions we allow main() to have non-integer return
// type, but we should warn about the extension, and we disable the
@@ -10000,14 +9906,9 @@ namespace {
void VisitCallExpr(CallExpr *E) {
// Treat std::move as a use.
- if (E->getNumArgs() == 1) {
- if (FunctionDecl *FD = E->getDirectCallee()) {
- if (FD->isInStdNamespace() && FD->getIdentifier() &&
- FD->getIdentifier()->isStr("move")) {
- HandleValue(E->getArg(0));
- return;
- }
- }
+ if (E->isCallToStdMove()) {
+ HandleValue(E->getArg(0));
+ return;
}
Inherited::VisitCallExpr(E);
@@ -10737,7 +10638,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (Var->isStaticDataMember()) {
// C++1z removes the relevant rule; the in-class declaration is always
// a definition there.
- if (!getLangOpts().CPlusPlus1z) {
+ if (!getLangOpts().CPlusPlus17) {
Diag(Var->getLocation(),
diag::err_constexpr_static_mem_var_requires_init)
<< Var->getDeclName();
@@ -10751,17 +10652,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
}
}
- // C++ Concepts TS [dcl.spec.concept]p1: [...] A variable template
- // definition having the concept specifier is called a variable concept. A
- // concept definition refers to [...] a variable concept and its initializer.
- if (VarTemplateDecl *VTD = Var->getDescribedVarTemplate()) {
- if (VTD->isConcept()) {
- Diag(Var->getLocation(), diag::err_var_concept_not_initialized);
- Var->setInvalidDecl();
- return;
- }
- }
-
// OpenCL v1.1 s6.5.3: variables declared in the constant address space must
// be initialized.
if (!Var->isInvalidDecl() &&
@@ -11651,6 +11541,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
StorageClass SC = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
SC = SC_Register;
+ // In C++11, the 'register' storage class specifier is deprecated.
+ // In C++17, it is not allowed, but we tolerate it as an extension.
+ if (getLangOpts().CPlusPlus11) {
+ Diag(DS.getStorageClassSpecLoc(),
+ getLangOpts().CPlusPlus17 ? diag::ext_register_storage_class
+ : diag::warn_deprecated_register)
+ << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
+ }
} else if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
SC = SC_Auto;
@@ -11665,12 +11563,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
<< DeclSpec::getSpecifierName(TSCS);
if (DS.isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
- << getLangOpts().CPlusPlus1z;
+ << getLangOpts().CPlusPlus17;
if (DS.isConstexprSpecified())
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 0;
- if (DS.isConceptSpecified())
- Diag(DS.getConceptSpecLoc(), diag::err_concept_wrong_decl_kind);
DiagnoseFunctionSpecifiers(DS);
@@ -11704,7 +11600,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Check for redeclaration of parameters, e.g. int foo(int x, int x);
if (II) {
LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
LookupName(R, S);
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
@@ -11873,13 +11769,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
- if (T.getAddressSpace() != 0) {
- // OpenCL allows function arguments declared to be an array of a type
- // to be qualified with an address space.
- if (!(getLangOpts().OpenCL && T->isArrayType())) {
- Diag(NameLoc, diag::err_arg_with_address_space);
- New->setInvalidDecl();
- }
+ if (T.getAddressSpace() != LangAS::Default &&
+ // OpenCL allows function arguments declared to be an array of a type
+ // to be qualified with an address space.
+ !(getLangOpts().OpenCL &&
+ (T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private))) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
}
return New;
@@ -12346,18 +12242,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
}
- // The only way to be included in UndefinedButUsed is if there is an
- // ODR use before the definition. Avoid the expensive map lookup if this
- // is the first declaration.
- if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) {
- if (!FD->isExternallyVisible())
- UndefinedButUsed.erase(FD);
- else if (FD->isInlined() &&
- !LangOpts.GNUInline &&
- (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>()))
- UndefinedButUsed.erase(FD);
- }
-
// If the function implicitly returns zero (like 'main') or is naked,
// don't complain about missing return statements.
if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>())
@@ -12621,28 +12505,50 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
IdentifierInfo &II, Scope *S) {
+ Scope *BlockScope = S;
+ while (!BlockScope->isCompoundStmtScope() && BlockScope->getParent())
+ BlockScope = BlockScope->getParent();
+
// Before we produce a declaration for an implicitly defined
// function, see whether there was a locally-scoped declaration of
// this name as a function or variable. If so, use that
// (non-visible) declaration, and complain about it.
- if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) {
- Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev;
- Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
- return ExternCPrev;
+ NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II);
+ if (ExternCPrev) {
+ // We still need to inject the function into the enclosing block scope so
+ // that later (non-call) uses can see it.
+ PushOnScopeChains(ExternCPrev, BlockScope, /*AddToContext*/false);
+
+ // C89 footnote 38:
+ // If in fact it is not defined as having type "function returning int",
+ // the behavior is undefined.
+ if (!isa<FunctionDecl>(ExternCPrev) ||
+ !Context.typesAreCompatible(
+ cast<FunctionDecl>(ExternCPrev)->getType(),
+ Context.getFunctionNoProtoType(Context.IntTy))) {
+ Diag(Loc, diag::ext_use_out_of_scope_declaration)
+ << ExternCPrev << !getLangOpts().C99;
+ Diag(ExternCPrev->getLocation(), diag::note_previous_declaration);
+ return ExternCPrev;
+ }
}
// Extension in C99. Legal in C90, but warn about it.
+ // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported.
unsigned diag_id;
if (II.getName().startswith("__builtin_"))
diag_id = diag::warn_builtin_unknown;
- // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported.
- else if (getLangOpts().OpenCL)
- diag_id = diag::err_opencl_implicit_function_decl;
- else if (getLangOpts().C99)
+ else if (getLangOpts().C99 || getLangOpts().OpenCL)
diag_id = diag::ext_implicit_function_decl;
else
diag_id = diag::warn_implicit_function_decl;
- Diag(Loc, diag_id) << &II;
+ Diag(Loc, diag_id) << &II << getLangOpts().OpenCL;
+
+ // If we found a prior declaration of this function, don't bother building
+ // another one. We've already pushed that one into scope, so there's nothing
+ // more to do.
+ if (ExternCPrev)
+ return ExternCPrev;
// Because typo correction is expensive, only do it if the implicit
// function declaration is going to be treated as an error.
@@ -12694,16 +12600,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
SourceLocation());
D.SetIdentifier(&II, Loc);
- // Insert this function into translation-unit scope.
-
- DeclContext *PrevDC = CurContext;
- CurContext = Context.getTranslationUnitDecl();
-
- FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
+ // Insert this function into the enclosing block scope.
+ FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(BlockScope, D));
FD->setImplicit();
- CurContext = PrevDC;
-
AddKnownFunctionAttributes(FD);
return FD;
@@ -12752,15 +12652,33 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
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.
- if (!getLangOpts().MathErrno &&
- Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
- if (!FD->hasAttr<ConstAttr>())
+ // 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.
+ if (!getLangOpts().MathErrno && !FD->hasAttr<ConstAttr>() &&
+ Context.BuiltinInfo.isConstWithoutErrno(BuiltinID))
+ FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
+
+ // We make "fma" on GNU or Windows const because we know it does not set
+ // errno in those environments even though it could set errno based on the
+ // C standard.
+ const llvm::Triple &Trip = Context.getTargetInfo().getTriple();
+ if ((Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) &&
+ !FD->hasAttr<ConstAttr>()) {
+ switch (BuiltinID) {
+ case Builtin::BI__builtin_fma:
+ case Builtin::BI__builtin_fmaf:
+ case Builtin::BI__builtin_fmal:
+ case Builtin::BIfma:
+ case Builtin::BIfmaf:
+ case Builtin::BIfmal:
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
+ break;
+ default:
+ break;
+ }
}
-
+
if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
!FD->hasAttr<ReturnsTwiceAttr>())
FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context,
@@ -13260,7 +13178,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
bool isStdBadAlloc = false;
bool isStdAlignValT = false;
- RedeclarationKind Redecl = ForRedeclaration;
+ RedeclarationKind Redecl = forRedeclarationInCurContext();
if (TUK == TUK_Friend || TUK == TUK_Reference)
Redecl = NotForRedeclaration;
@@ -13538,10 +13456,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// type declared by an elaborated-type-specifier. In C that is not correct
// and we should instead merge compatible types found by lookup.
if (getLangOpts().CPlusPlus) {
- Previous.setRedeclarationKind(ForRedeclaration);
+ Previous.setRedeclarationKind(forRedeclarationInCurContext());
LookupQualifiedName(Previous, SearchDC);
} else {
- Previous.setRedeclarationKind(ForRedeclaration);
+ Previous.setRedeclarationKind(forRedeclarationInCurContext());
LookupName(Previous, S);
}
}
@@ -13941,6 +13859,13 @@ CreateNewDecl:
Invalid = true;
}
+ if (!Invalid && getLangOpts().CPlusPlus && TUK == TUK_Definition &&
+ DC->getDeclKind() == Decl::Enum) {
+ Diag(New->getLocation(), diag::err_type_defined_in_enum)
+ << Context.getTagDeclType(New);
+ Invalid = true;
+ }
+
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
if (SS.isSet()) {
@@ -14032,6 +13957,9 @@ CreateNewDecl:
if (!Invalid && SearchDC->isRecord())
SetMemberAccessSpecifier(New, PrevDecl, AS);
+ if (PrevDecl)
+ CheckRedeclarationModuleOwnership(New, PrevDecl);
+
if (TUK == TUK_Definition)
New->startDefinition();
@@ -14358,7 +14286,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
}
// TR 18037 does not allow fields to be declared with address spaces.
- if (T.getQualifiers().hasAddressSpace()) {
+ if (T.getQualifiers().hasAddressSpace() ||
+ T->isDependentAddressSpaceType() ||
+ T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) {
Diag(Loc, diag::err_field_with_address_space);
D.setInvalidType();
}
@@ -14375,7 +14305,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
- << getLangOpts().CPlusPlus1z;
+ << getLangOpts().CPlusPlus17;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)
@@ -14383,7 +14313,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = nullptr;
- LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
+ LookupResult Previous(*this, II, Loc, LookupMemberName,
+ ForVisibleRedeclaration);
LookupName(Previous, S);
switch (Previous.getResultKind()) {
case LookupResult::Found:
@@ -14771,7 +14702,7 @@ Decl *Sema::ActOnIvar(Scope *S,
if (II) {
NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
Diag(Loc, diag::err_duplicate_member) << II;
@@ -14913,6 +14844,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// possibly recursively, a member that is such a structure)
// shall not be a member of a structure or an element of an
// array.
+ bool IsLastField = (i + 1 == Fields.end());
if (FDTy->isFunctionType()) {
// Field declared as a function.
Diag(FD->getLocation(), diag::err_field_declared_as_function)
@@ -14920,60 +14852,70 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (FDTy->isIncompleteArrayType() && Record &&
- ((i + 1 == Fields.end() && !Record->isUnion()) ||
- ((getLangOpts().MicrosoftExt ||
- getLangOpts().CPlusPlus) &&
- (i + 1 == Fields.end() || Record->isUnion())))) {
- // Flexible array member.
- // Microsoft and g++ is more permissive regarding flexible array.
- // It will accept flexible array in union and also
- // as the sole element of a struct/class.
- unsigned DiagID = 0;
- if (Record->isUnion())
- DiagID = getLangOpts().MicrosoftExt
- ? diag::ext_flexible_array_union_ms
- : getLangOpts().CPlusPlus
- ? diag::ext_flexible_array_union_gnu
- : diag::err_flexible_array_union;
- else if (NumNamedMembers < 1)
- DiagID = getLangOpts().MicrosoftExt
- ? diag::ext_flexible_array_empty_aggregate_ms
- : getLangOpts().CPlusPlus
- ? diag::ext_flexible_array_empty_aggregate_gnu
- : diag::err_flexible_array_empty_aggregate;
-
- if (DiagID)
- Diag(FD->getLocation(), DiagID) << FD->getDeclName()
- << Record->getTagKind();
- // While the layout of types that contain virtual bases is not specified
- // by the C++ standard, both the Itanium and Microsoft C++ ABIs place
- // virtual bases after the derived members. This would make a flexible
- // array member declared at the end of an object not adjacent to the end
- // of the type.
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record))
- if (RD->getNumVBases() != 0)
- Diag(FD->getLocation(), diag::err_flexible_array_virtual_base)
+ } else if (FDTy->isIncompleteArrayType() &&
+ (Record || isa<ObjCContainerDecl>(EnclosingDecl))) {
+ if (Record) {
+ // Flexible array member.
+ // Microsoft and g++ is more permissive regarding flexible array.
+ // It will accept flexible array in union and also
+ // as the sole element of a struct/class.
+ unsigned DiagID = 0;
+ if (!Record->isUnion() && !IsLastField) {
+ Diag(FD->getLocation(), diag::err_flexible_array_not_at_end)
+ << FD->getDeclName() << FD->getType() << Record->getTagKind();
+ Diag((*(i + 1))->getLocation(), diag::note_next_field_declaration);
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ } else if (Record->isUnion())
+ DiagID = getLangOpts().MicrosoftExt
+ ? diag::ext_flexible_array_union_ms
+ : getLangOpts().CPlusPlus
+ ? diag::ext_flexible_array_union_gnu
+ : diag::err_flexible_array_union;
+ else if (NumNamedMembers < 1)
+ DiagID = getLangOpts().MicrosoftExt
+ ? diag::ext_flexible_array_empty_aggregate_ms
+ : getLangOpts().CPlusPlus
+ ? diag::ext_flexible_array_empty_aggregate_gnu
+ : diag::err_flexible_array_empty_aggregate;
+
+ if (DiagID)
+ Diag(FD->getLocation(), DiagID) << FD->getDeclName()
+ << Record->getTagKind();
+ // While the layout of types that contain virtual bases is not specified
+ // by the C++ standard, both the Itanium and Microsoft C++ ABIs place
+ // virtual bases after the derived members. This would make a flexible
+ // array member declared at the end of an object not adjacent to the end
+ // of the type.
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record))
+ if (RD->getNumVBases() != 0)
+ Diag(FD->getLocation(), diag::err_flexible_array_virtual_base)
+ << FD->getDeclName() << Record->getTagKind();
+ if (!getLangOpts().C99)
+ Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
<< FD->getDeclName() << Record->getTagKind();
- if (!getLangOpts().C99)
- Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
- << FD->getDeclName() << Record->getTagKind();
- // If the element type has a non-trivial destructor, we would not
- // implicitly destroy the elements, so disallow it for now.
- //
- // FIXME: GCC allows this. We should probably either implicitly delete
- // the destructor of the containing class, or just allow this.
- QualType BaseElem = Context.getBaseElementType(FD->getType());
- if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) {
- Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor)
- << FD->getDeclName() << FD->getType();
- FD->setInvalidDecl();
- EnclosingDecl->setInvalidDecl();
- continue;
+ // If the element type has a non-trivial destructor, we would not
+ // implicitly destroy the elements, so disallow it for now.
+ //
+ // FIXME: GCC allows this. We should probably either implicitly delete
+ // the destructor of the containing class, or just allow this.
+ QualType BaseElem = Context.getBaseElementType(FD->getType());
+ if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) {
+ Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor)
+ << FD->getDeclName() << FD->getType();
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // Okay, we have a legal flexible array member at the end of the struct.
+ Record->setHasFlexibleArrayMember(true);
+ } else {
+ // In ObjCContainerDecl ivars with incomplete array type are accepted,
+ // unless they are followed by another ivar. That check is done
+ // elsewhere, after synthesized ivars are known.
}
- // Okay, we have a legal flexible array member at the end of the struct.
- Record->setHasFlexibleArrayMember(true);
} else if (!FDTy->isDependentType() &&
RequireCompleteType(FD->getLocation(), FD->getType(),
diag::err_field_incomplete)) {
@@ -14990,7 +14932,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// If this is a struct/class and this is not the last element, reject
// it. Note that GCC supports variable sized arrays in the middle of
// structures.
- if (i + 1 != Fields.end())
+ if (!IsLastField)
Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct)
<< FD->getDeclName() << FD->getType();
else {
@@ -15137,8 +15079,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
auto *Dtor = CXXRecord->getDestructor();
if (Dtor && Dtor->isImplicit() &&
- ShouldDeleteSpecialMember(Dtor, CXXDestructor))
+ ShouldDeleteSpecialMember(Dtor, CXXDestructor)) {
+ CXXRecord->setImplicitDestructorIsDeleted();
SetDeclDeleted(Dtor, CXXRecord->getLocation());
+ }
}
if (Record->hasAttrs()) {
@@ -15271,7 +15215,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
static bool isRepresentableIntegerValue(ASTContext &Context,
llvm::APSInt &Value,
QualType T) {
- assert(T->isIntegralType(Context) && "Integral type required!");
+ assert((T->isIntegralType(Context) || T->isEnumeralType()) &&
+ "Integral type required!");
unsigned BitWidth = Context.getIntWidth(T);
if (Value.isUnsigned() || Value.isNonNegative()) {
@@ -15287,7 +15232,8 @@ static bool isRepresentableIntegerValue(ASTContext &Context,
static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
// FIXME: Int128/UInt128 support, which also needs to be introduced into
// enum checking below.
- assert(T->isIntegralType(Context) && "Integral type required!");
+ assert((T->isIntegralType(Context) ||
+ T->isEnumeralType()) && "Integral type required!");
const unsigned NumTypes = 4;
QualType SignedIntegralTypes[NumTypes] = {
Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy
@@ -15326,7 +15272,6 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
- SourceLocation ExpLoc;
if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
!getLangOpts().MSVCCompat) {
// C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
@@ -15491,7 +15436,7 @@ Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
// determine if we should merge the definition with an existing one and
// skip the body.
NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
auto *PrevECD = dyn_cast_or_null<EnumConstantDecl>(PrevDecl);
if (!PrevECD)
return SkipBodyInfo();
@@ -15522,7 +15467,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// Verify that there isn't already something declared with this name in this
// scope.
NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
@@ -15549,8 +15494,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// enum constant will 'hide' the tag.
assert((getLangOpts().CPlusPlus || !isa<TagDecl>(PrevDecl)) &&
"Received TagDecl when not in C++!");
- if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S) &&
- shouldLinkPossiblyHiddenDecl(PrevDecl, New)) {
+ if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) {
if (isa<EnumConstantDecl>(PrevDecl))
Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
else
@@ -16043,7 +15987,7 @@ static void checkModuleImportContext(Sema &S, Module *M,
DC = LSD->getParent();
}
- while (isa<LinkageSpecDecl>(DC))
+ while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC))
DC = DC->getParent();
if (!isa<TranslationUnitDecl>(DC)) {
@@ -16064,6 +16008,9 @@ 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.
@@ -16080,6 +16027,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
// 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:
@@ -16087,9 +16035,19 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
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.
@@ -16100,8 +16058,6 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
ModuleName += Piece.first->getName();
}
- // FIXME: If we've already seen a module-declaration, report an error.
-
// If a module name was explicitly specified on the command line, it must be
// correct.
if (!getLangOpts().CurrentModule.empty() &&
@@ -16117,9 +16073,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
Module *Mod;
switch (MDK) {
- case ModuleDeclKind::Module: {
- // FIXME: Check we're not in a submodule.
-
+ 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)) {
@@ -16129,11 +16083,13 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
else if (const auto *FE = M->getASTFile())
Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
<< FE->getName();
- return nullptr;
+ Mod = M;
+ break;
}
// Create a Module for the module that we're defining.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ ModuleScopes.front().Module);
assert(Mod && "module creation should not fail");
break;
}
@@ -16147,21 +16103,26 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
PP.getIdentifierInfo(ModuleName), Path[0].second);
Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible,
/*IsIncludeDirective=*/false);
- if (!Mod)
- return nullptr;
+ 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;
}
- // Enter the semantic scope of the module.
- ModuleScopes.push_back({});
+ // Switch from the global module to the named module.
ModuleScopes.back().Module = Mod;
- ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
+ 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.
- Context.getTranslationUnitDecl()->setLocalOwningModule(Mod);
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ TU->setLocalOwningModule(Mod);
// FIXME: Create a ModuleDecl.
return nullptr;
@@ -16204,12 +16165,17 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
IdentifierLocs.push_back(Path[I].second);
}
- TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
- ImportDecl *Import = ImportDecl::Create(Context, TU, StartLoc,
+ ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc,
Mod, IdentifierLocs);
if (!ModuleScopes.empty())
Context.addModuleInitializer(ModuleScopes.back().Module, Import);
- TU->addDecl(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;
}
@@ -16339,8 +16305,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation 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().Module ||
- ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)
+ if (ModuleScopes.empty() || !ModuleScopes.back().ModuleInterface)
Diag(ExportLoc, diag::err_export_not_in_module_interface);
// An export-declaration [...] shall not contain more than one
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 2a310bf41c70..676d00357c96 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -540,14 +540,13 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
// a DeclRefExpr is found, its type should be checked to determine whether it
// is a capability or not.
- if (const auto *E = dyn_cast<DeclRefExpr>(Ex))
- return typeHasCapability(S, E->getType());
- else if (const auto *E = dyn_cast<CastExpr>(Ex))
+ if (const auto *E = dyn_cast<CastExpr>(Ex))
return isCapabilityExpr(S, E->getSubExpr());
else if (const auto *E = dyn_cast<ParenExpr>(Ex))
return isCapabilityExpr(S, E->getSubExpr());
else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) {
- if (E->getOpcode() == UO_LNot)
+ if (E->getOpcode() == UO_LNot || E->getOpcode() == UO_AddrOf ||
+ E->getOpcode() == UO_Deref)
return isCapabilityExpr(S, E->getSubExpr());
return false;
} else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) {
@@ -557,7 +556,7 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
return false;
}
- return false;
+ return typeHasCapability(S, Ex->getType());
}
/// \brief Checks that all attribute arguments, starting from Sidx, resolve to
@@ -1304,14 +1303,28 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- // Report warning about changed offset in the newer compiler versions.
- if (!FD->getType()->isDependentType() &&
- !FD->getType()->isIncompleteType() && FD->isBitField() &&
- S.Context.getTypeAlign(FD->getType()) <= 8)
- S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield);
+ bool BitfieldByteAligned = (!FD->getType()->isDependentType() &&
+ !FD->getType()->isIncompleteType() &&
+ FD->isBitField() &&
+ S.Context.getTypeAlign(FD->getType()) <= 8);
+
+ if (S.getASTContext().getTargetInfo().getTriple().isPS4()) {
+ if (BitfieldByteAligned)
+ // The PS4 target needs to maintain ABI backwards compatibility.
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
+ << Attr.getName() << FD->getType();
+ else
+ FD->addAttr(::new (S.Context) PackedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+ } else {
+ // Report warning about changed offset in the newer compiler versions.
+ if (BitfieldByteAligned)
+ S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield);
+
+ FD->addAttr(::new (S.Context) PackedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+ }
- FD->addAttr(::new (S.Context) PackedAttr(
- Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -1517,6 +1530,22 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (D->isInvalidDecl())
+ return;
+
+ // noescape only applies to pointer types.
+ QualType T = cast<ParmVarDecl>(D)->getType();
+ if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only)
+ << Attr.getName() << Attr.getRange() << 0;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoEscapeAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
static void handleAssumeAlignedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
Expr *E = Attr.getArgAsExpr(0),
@@ -1939,20 +1968,20 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
+static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) {
if (hasDeclarator(D)) return;
- if (S.CheckNoReturnAttr(attr))
+ if (S.CheckNoReturnAttr(Attrs))
return;
if (!isa<ObjCMethodDecl>(D)) {
- S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attrs.getName() << ExpectedFunctionOrMethod;
return;
}
D->addAttr(::new (S.Context) NoReturnAttr(
- attr.getRange(), S.Context, attr.getAttributeSpellingListIndex()));
+ Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
}
static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D,
@@ -1964,9 +1993,9 @@ static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D,
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
-bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
- if (!checkAttributeNumArgs(*this, attr, 0)) {
- attr.setInvalid();
+bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) {
+ if (!checkAttributeNumArgs(*this, Attrs, 0)) {
+ Attrs.setInvalid();
return true;
}
@@ -2122,10 +2151,10 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- bool IsCXX1zAttr = Attr.isCXX11Attribute() && !Attr.getScopeName();
+ bool IsCXX17Attr = Attr.isCXX11Attribute() && !Attr.getScopeName();
- if (IsCXX1zAttr && isa<VarDecl>(D)) {
- // The C++1z spelling of this attribute cannot be applied to a static data
+ if (IsCXX17Attr && isa<VarDecl>(D)) {
+ // The C++17 spelling of this attribute cannot be applied to a static data
// member per [dcl.attr.unused]p2.
if (cast<VarDecl>(D)->isStaticDataMember()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
@@ -2134,10 +2163,10 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
- // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // If this is spelled as the standard C++17 attribute, but not in C++17, warn
// about using it as an extension.
- if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr)
- S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
+ if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr)
+ S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName();
D->addAttr(::new (S.Context) UnusedAttr(
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
@@ -2831,11 +2860,11 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
return;
}
- // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // If this is spelled as the standard C++17 attribute, but not in C++17, warn
// about using it as an extension.
- if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() &&
+ if (!S.getLangOpts().CPlusPlus17 && Attr.isCXX11Attribute() &&
!Attr.getScopeName())
- S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
+ S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName();
D->addAttr(::new (S.Context)
WarnUnusedResultAttr(Attr.getRange(), S.Context,
@@ -2993,22 +3022,43 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(NewAttr);
}
-// Check for things we'd like to warn about, no errors or validation for now.
-// TODO: Validation should use a backend target library that specifies
-// the allowable subtarget features and cpus. We could use something like a
-// TargetCodeGenInfo hook here to do validation.
-void Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
+// Check for things we'd like to warn about. Multiversioning issues are
+// handled later in the process, once we know how many exist.
+bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
+ enum FirstParam { Unsupported, Duplicate };
+ enum SecondParam { None, Architecture };
for (auto Str : {"tune=", "fpmath="})
if (AttrStr.find(Str) != StringRef::npos)
- Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Str;
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << Str;
+
+ TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
+
+ if (!ParsedAttrs.Architecture.empty() &&
+ !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << Architecture << ParsedAttrs.Architecture;
+
+ if (ParsedAttrs.DuplicateArchitecture)
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Duplicate << None << "arch=";
+
+ for (const auto &Feature : ParsedAttrs.Features) {
+ auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
+ if (!Context.getTargetInfo().isValidFeatureName(CurFeature))
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << CurFeature;
+ }
+
+ return true;
}
static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) {
StringRef Str;
SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc))
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc) ||
+ !S.checkTargetAttr(LiteralLoc, Str))
return;
- S.checkTargetAttr(LiteralLoc, Str);
unsigned Index = Attr.getAttributeSpellingListIndex();
TargetAttr *NewAttr =
::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index);
@@ -3016,12 +3066,6 @@ static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- VarDecl *VD = cast<VarDecl>(D);
- if (!VD->hasLocalStorage()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
- return;
- }
-
Expr *E = Attr.getArgAsExpr(0);
SourceLocation Loc = E->getExprLoc();
FunctionDecl *FD = nullptr;
@@ -3064,7 +3108,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// We're currently more strict than GCC about what function types we accept.
// If this ever proves to be a problem it should be easy to fix.
- QualType Ty = S.Context.getPointerType(VD->getType());
+ QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType());
QualType ParamTy = FD->getParamDecl(0)->getType();
if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),
ParamTy, Ty) != Sema::Compatible) {
@@ -4252,24 +4296,24 @@ static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) {
DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex()));
}
-bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
+bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC,
const FunctionDecl *FD) {
- if (attr.isInvalid())
+ if (Attrs.isInvalid())
return true;
- if (attr.hasProcessingCache()) {
- CC = (CallingConv) attr.getProcessingCache();
+ if (Attrs.hasProcessingCache()) {
+ CC = (CallingConv) Attrs.getProcessingCache();
return false;
}
- unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0;
- if (!checkAttributeNumArgs(*this, attr, ReqArgs)) {
- attr.setInvalid();
+ unsigned ReqArgs = Attrs.getKind() == AttributeList::AT_Pcs ? 1 : 0;
+ if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) {
+ Attrs.setInvalid();
return true;
}
// TODO: diagnose uses of these conventions on the wrong target.
- switch (attr.getKind()) {
+ switch (Attrs.getKind()) {
case AttributeList::AT_CDecl: CC = CC_C; break;
case AttributeList::AT_FastCall: CC = CC_X86FastCall; break;
case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
@@ -4288,8 +4332,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
break;
case AttributeList::AT_Pcs: {
StringRef StrRef;
- if (!checkStringLiteralArgumentAttr(attr, 0, StrRef)) {
- attr.setInvalid();
+ if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) {
+ Attrs.setInvalid();
return true;
}
if (StrRef == "aapcs") {
@@ -4300,8 +4344,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
break;
}
- attr.setInvalid();
- Diag(attr.getLoc(), diag::err_invalid_pcs);
+ Attrs.setInvalid();
+ Diag(Attrs.getLoc(), diag::err_invalid_pcs);
return true;
}
case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break;
@@ -4314,7 +4358,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
if (A != TargetInfo::CCCR_OK) {
if (A == TargetInfo::CCCR_Warning)
- Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName();
+ Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs.getName();
// This convention is not valid for the target. Use the default function or
// method calling convention.
@@ -4326,7 +4370,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
}
- attr.setProcessingCache((unsigned) CC);
+ Attrs.setProcessingCache((unsigned) CC);
return false;
}
@@ -4334,7 +4378,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
static bool isValidSwiftContextType(QualType type) {
if (!type->hasPointerRepresentation())
return type->isDependentType();
- return type->getPointeeType().getAddressSpace() == 0;
+ return type->getPointeeType().getAddressSpace() == LangAS::Default;
}
/// Pointers and references in the default address space.
@@ -4346,7 +4390,7 @@ static bool isValidSwiftIndirectResultType(QualType type) {
} else {
return type->isDependentType();
}
- return type.getAddressSpace() == 0;
+ return type.getAddressSpace() == LangAS::Default;
}
/// Pointers and references to pointers in the default address space.
@@ -4363,10 +4407,10 @@ static bool isValidSwiftErrorResultType(QualType type) {
return isValidSwiftContextType(type);
}
-static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &attr,
- ParameterABI abi) {
- S.AddParameterABIAttr(attr.getRange(), D, abi,
- attr.getAttributeSpellingListIndex());
+static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &Attrs,
+ ParameterABI Abi) {
+ S.AddParameterABIAttr(Attrs.getRange(), D, Abi,
+ Attrs.getAttributeSpellingListIndex());
}
void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
@@ -4807,11 +4851,11 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
}
static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
- const AttributeList &attr) {
+ const AttributeList &Attrs) {
const int EP_ObjCMethod = 1;
const int EP_ObjCProperty = 2;
- SourceLocation loc = attr.getLoc();
+ SourceLocation loc = Attrs.getLoc();
QualType resultType;
if (isa<ObjCMethodDecl>(D))
resultType = cast<ObjCMethodDecl>(D)->getReturnType();
@@ -4822,7 +4866,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
(!resultType->isPointerType() || resultType->isObjCRetainableType())) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
<< SourceRange(loc)
- << attr.getName()
+ << Attrs.getName()
<< (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty)
<< /*non-retainable pointer*/ 2;
@@ -4831,29 +4875,29 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(
- attr.getRange(), S.Context, attr.getAttributeSpellingListIndex()));
+ Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
- const AttributeList &attr) {
+ const AttributeList &Attrs) {
ObjCMethodDecl *method = cast<ObjCMethodDecl>(D);
DeclContext *DC = method->getDeclContext();
if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
- << attr.getName() << 0;
+ << Attrs.getName() << 0;
S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
return;
}
if (method->getMethodFamily() == OMF_dealloc) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
- << attr.getName() << 1;
+ << Attrs.getName() << 1;
return;
}
method->addAttr(::new (S.Context)
- ObjCRequiresSuperAttr(attr.getRange(), S.Context,
- attr.getAttributeSpellingListIndex()));
+ ObjCRequiresSuperAttr(Attrs.getRange(), S.Context,
+ Attrs.getAttributeSpellingListIndex()));
}
static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
@@ -5665,8 +5709,12 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleAssertCapabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context,
- Attr.getArgAsExpr(0),
+ Args.data(), Args.size(),
Attr.getAttributeSpellingListIndex()));
}
@@ -5965,6 +6013,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_NoMicroMips:
handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr);
break;
+ case AttributeList::AT_MipsLongCall:
+ handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>(
+ S, D, Attr);
+ break;
+ case AttributeList::AT_MipsShortCall:
+ handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>(
+ S, D, Attr);
+ break;
case AttributeList::AT_AMDGPUFlatWorkGroupSize:
handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr);
break;
@@ -6120,6 +6176,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReturnsNonNull:
handleReturnsNonNullAttr(S, D, Attr);
break;
+ case AttributeList::AT_NoEscape:
+ handleNoEscapeAttr(S, D, Attr);
+ break;
case AttributeList::AT_AssumeAligned:
handleAssumeAlignedAttr(S, D, Attr);
break;
@@ -7003,6 +7062,49 @@ static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
return dyn_cast<NamedDecl>(OrigCtx);
}
+namespace {
+
+struct AttributeInsertion {
+ StringRef Prefix;
+ SourceLocation Loc;
+ StringRef Suffix;
+
+ static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
+ return {" ", D->getLocEnd(), ""};
+ }
+ static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
+ return {" ", Loc, ""};
+ }
+ static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
+ return {"", D->getLocStart(), "\n"};
+ }
+};
+
+} // end anonymous namespace
+
+/// Returns a source location in which it's appropriate to insert a new
+/// attribute for the given declaration \D.
+static Optional<AttributeInsertion>
+createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (isa<ObjCPropertyDecl>(D))
+ return AttributeInsertion::createInsertionAfter(D);
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->hasBody())
+ return None;
+ return AttributeInsertion::createInsertionAfter(D);
+ }
+ if (const auto *TD = dyn_cast<TagDecl>(D)) {
+ SourceLocation Loc =
+ Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
+ if (Loc.isInvalid())
+ return None;
+ // Insert after the 'struct'/whatever keyword.
+ return AttributeInsertion::createInsertionAfter(Loc);
+ }
+ return AttributeInsertion::createInsertionBefore(D);
+}
+
/// Actually emit an availability diagnostic for a reference to an unavailable
/// decl.
///
@@ -7038,7 +7140,83 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
return;
+ // The declaration can have multiple availability attributes, we are looking
+ // at one of them.
+ const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
+ if (A && A->isInherited()) {
+ for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
+ Redecl = Redecl->getPreviousDecl()) {
+ const AvailabilityAttr *AForRedecl =
+ getAttrForPlatform(S.Context, Redecl);
+ if (AForRedecl && !AForRedecl->isInherited()) {
+ // If D is a declaration with inherited attributes, the note should
+ // point to the declaration with actual attributes.
+ NoteLocation = Redecl->getLocation();
+ break;
+ }
+ }
+ }
+
switch (K) {
+ case AR_NotYetIntroduced: {
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(S.getASTContext(), OffendingDecl);
+ VersionTuple Introduced = AA->getIntroduced();
+
+ bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
+ S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
+ Introduced);
+ unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ S.Diag(Loc, Warning)
+ << OffendingDecl
+ << AvailabilityAttr::getPrettyPlatformName(
+ S.getASTContext().getTargetInfo().getPlatformName())
+ << Introduced.getAsString();
+
+ S.Diag(OffendingDecl->getLocation(), diag::note_availability_specified_here)
+ << OffendingDecl << /* partial */ 3;
+
+ if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
+ if (auto *TD = dyn_cast<TagDecl>(Enclosing))
+ if (TD->getDeclName().isEmpty()) {
+ S.Diag(TD->getLocation(),
+ diag::note_decl_unguarded_availability_silence)
+ << /*Anonymous*/ 1 << TD->getKindName();
+ return;
+ }
+ auto FixitNoteDiag =
+ S.Diag(Enclosing->getLocation(),
+ diag::note_decl_unguarded_availability_silence)
+ << /*Named*/ 0 << Enclosing;
+ // Don't offer a fixit for declarations with availability attributes.
+ if (Enclosing->hasAttr<AvailabilityAttr>())
+ return;
+ if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
+ return;
+ Optional<AttributeInsertion> Insertion = createAttributeInsertion(
+ Enclosing, S.getSourceManager(), S.getLangOpts());
+ if (!Insertion)
+ return;
+ std::string PlatformName =
+ AvailabilityAttr::getPlatformNameSourceSpelling(
+ S.getASTContext().getTargetInfo().getPlatformName())
+ .lower();
+ std::string Introduced =
+ OffendingDecl->getVersionIntroduced().getAsString();
+ FixitNoteDiag << FixItHint::CreateInsertion(
+ Insertion->Loc,
+ (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
+ "(" + Introduced + "))" + Insertion->Suffix)
+ .str());
+ }
+ return;
+ }
case AR_Deprecated:
diag = !ObjCPropertyAccess ? diag::warn_deprecated
: diag::warn_property_method_deprecated;
@@ -7046,8 +7224,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
property_note_select = /* deprecated */ 0;
available_here_select_kind = /* deprecated */ 2;
- if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>())
- NoteLocation = attr->getLocation();
+ if (const auto *Attr = OffendingDecl->getAttr<DeprecatedAttr>())
+ NoteLocation = Attr->getLocation();
break;
case AR_Unavailable:
@@ -7058,8 +7236,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
property_note_select = /* unavailable */ 1;
available_here_select_kind = /* unavailable */ 0;
- if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) {
- if (attr->isImplicit() && attr->getImplicitReason()) {
+ if (auto Attr = OffendingDecl->getAttr<UnavailableAttr>()) {
+ if (Attr->isImplicit() && Attr->getImplicitReason()) {
// Most of these failures are due to extra restrictions in ARC;
// reflect that in the primary diagnostic when applicable.
auto flagARCError = [&] {
@@ -7069,7 +7247,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
diag = diag::err_unavailable_in_arc;
};
- switch (attr->getImplicitReason()) {
+ switch (Attr->getImplicitReason()) {
case UnavailableAttr::IR_None: break;
case UnavailableAttr::IR_ARCForbiddenType:
@@ -7103,28 +7281,6 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
break;
- case AR_NotYetIntroduced: {
- // We would like to emit the diagnostic even if -Wunguarded-availability is
- // not specified for deployment targets >= to iOS 11 or equivalent or
- // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
- // later.
- const AvailabilityAttr *AA =
- getAttrForPlatform(S.getASTContext(), OffendingDecl);
- VersionTuple Introduced = AA->getIntroduced();
- bool NewWarning = shouldDiagnoseAvailabilityByDefault(
- S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
- Introduced);
- diag = NewWarning ? diag::warn_partial_availability_new
- : diag::warn_partial_availability;
- diag_message = NewWarning ? diag::warn_partial_message_new
- : diag::warn_partial_message;
- diag_fwdclass_message = NewWarning ? diag::warn_partial_fwdclass_message_new
- : diag::warn_partial_fwdclass_message;
- property_note_select = /* partial */ 2;
- available_here_select_kind = /* partial */ 3;
- break;
- }
-
case AR_Available:
llvm_unreachable("Warning for availability of available declaration?");
}
@@ -7132,10 +7288,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
CharSourceRange UseRange;
StringRef Replacement;
if (K == AR_Deprecated) {
- if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>())
- Replacement = attr->getReplacement();
- if (auto attr = getAttrForPlatform(S.Context, OffendingDecl))
- Replacement = attr->getReplacement();
+ if (auto Attr = OffendingDecl->getAttr<DeprecatedAttr>())
+ Replacement = Attr->getReplacement();
+ if (auto Attr = getAttrForPlatform(S.Context, OffendingDecl))
+ Replacement = Attr->getReplacement();
if (!Replacement.empty())
UseRange =
@@ -7163,38 +7319,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
}
- // The declaration can have multiple availability attributes, we are looking
- // at one of them.
- const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
- if (A && A->isInherited()) {
- for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
- Redecl = Redecl->getPreviousDecl()) {
- const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
- Redecl);
- if (AForRedecl && !AForRedecl->isInherited()) {
- // If D is a declaration with inherited attributes, the note should
- // point to the declaration with actual attributes.
- S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl
- << available_here_select_kind;
- break;
- }
- }
- }
- else
- S.Diag(NoteLocation, diag_available_here)
- << OffendingDecl << available_here_select_kind;
-
- if (K == AR_NotYetIntroduced)
- if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
- if (auto *TD = dyn_cast<TagDecl>(Enclosing))
- if (TD->getDeclName().isEmpty()) {
- S.Diag(TD->getLocation(), diag::note_partial_availability_silence)
- << /*Anonymous*/1 << TD->getKindName();
- return;
- }
- S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence)
- << /*Named*/0 << Enclosing;
- }
+ S.Diag(NoteLocation, diag_available_here)
+ << OffendingDecl << available_here_select_kind;
}
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
@@ -7399,6 +7525,10 @@ public:
bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
+ // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
+ // to any useful diagnostics.
+ bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
+
bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
if (PRE->isClassReceiver())
DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
@@ -7581,8 +7711,7 @@ bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
// If we're using the '*' case here or if this check is redundant, then we
// use the enclosing version to check both branches.
if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
- return Base::TraverseStmt(If->getThen()) &&
- Base::TraverseStmt(If->getElse());
+ return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
} else {
// This isn't an availability checking 'if', we can just continue.
return Base::TraverseIfStmt(If);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 28323f365af7..96472a0a70fe 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -143,7 +143,7 @@ namespace {
if (Lambda->capture_begin() == Lambda->capture_end())
return false;
- return S->Diag(Lambda->getLocStart(),
+ return S->Diag(Lambda->getLocStart(),
diag::err_lambda_capture_default_arg);
}
}
@@ -167,6 +167,9 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
if (ComputedEST == EST_None)
return;
+ if (EST == EST_None && Method->hasAttr<NoThrowAttr>())
+ EST = EST_BasicNoexcept;
+
switch(EST) {
// If this function can throw any exceptions, make a note of that.
case EST_MSAny:
@@ -276,18 +279,18 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
// Okay: add the default argument to the parameter
Param->setDefaultArg(Arg);
- // We have already instantiated this parameter; provide each of the
+ // We have already instantiated this parameter; provide each of the
// instantiations with the uninstantiated default argument.
UnparsedDefaultArgInstantiationsMap::iterator InstPos
= UnparsedDefaultArgInstantiations.find(Param);
if (InstPos != UnparsedDefaultArgInstantiations.end()) {
for (unsigned I = 0, N = InstPos->second.size(); I != N; ++I)
InstPos->second[I]->setUninstantiatedDefaultArg(Arg);
-
+
// We're done tracking this parameter's instantiations.
UnparsedDefaultArgInstantiations.erase(InstPos);
}
-
+
return false;
}
@@ -524,8 +527,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = false;
}
}
-
- // FIXME: If we knew where the '=' was, we could easily provide a fix-it
+
+ // FIXME: If we knew where the '=' was, we could easily provide a fix-it
// hint here. Alternatively, we could walk the type-source information
// for NewParam to find the last source location in the type... but it
// isn't worth the effort right now. This is the kind of test case that
@@ -535,7 +538,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// void g(int (*fp)(int) = &f);
Diag(NewParam->getLocation(), DiagDefaultParamID)
<< NewParam->getDefaultArgRange();
-
+
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
for (auto Older = PrevForDefaultArgs;
@@ -581,9 +584,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// or a definition for one of the following explicit specializations:
// - the explicit specialization of a function template;
// - the explicit specialization of a member function template;
- // - the explicit specialization of a member function of a class
+ // - the explicit specialization of a member function of a class
// template where the class template specialization to which the
- // member function specialization belongs is implicitly
+ // member function specialization belongs is implicitly
// instantiated.
Diag(NewParam->getLocation(), diag::err_template_spec_default_arg)
<< (New->getTemplateSpecializationKind() ==TSK_ExplicitSpecialization)
@@ -591,16 +594,16 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
<< NewParam->getDefaultArgRange();
} else if (New->getDeclContext()->isDependentContext()) {
// C++ [dcl.fct.default]p6 (DR217):
- // Default arguments for a member function of a class template shall
- // be specified on the initial declaration of the member function
+ // Default arguments for a member function of a class template shall
+ // be specified on the initial declaration of the member function
// within the class template.
//
- // Reading the tea leaves a bit in DR217 and its reference to DR205
- // leads me to the conclusion that one cannot add default function
- // arguments for an out-of-line definition of a member function of a
+ // Reading the tea leaves a bit in DR217 and its reference to DR205
+ // leads me to the conclusion that one cannot add default function
+ // arguments for an out-of-line definition of a member function of a
// dependent type.
int WhichKind = 2;
- if (CXXRecordDecl *Record
+ if (CXXRecordDecl *Record
= dyn_cast<CXXRecordDecl>(New->getDeclContext())) {
if (Record->getDescribedClassTemplate())
WhichKind = 0;
@@ -609,8 +612,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
else
WhichKind = 2;
}
-
- Diag(NewParam->getLocation(),
+
+ Diag(NewParam->getLocation(),
diag::err_param_default_argument_member_template_redecl)
<< WhichKind
<< NewParam->getDefaultArgRange();
@@ -689,8 +692,9 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
assert(D.isDecompositionDeclarator());
const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
- // The syntax only allows a decomposition declarator as a simple-declaration
- // or a for-range-declaration, but we parse it in more cases than that.
+ // The syntax only allows a decomposition declarator as a simple-declaration,
+ // a for-range-declaration, or a condition in Clang, but we parse it in more
+ // cases than that.
if (!D.mayHaveDecompositionDeclarator()) {
Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
<< Decomp.getSourceRange();
@@ -705,9 +709,12 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
return nullptr;
}
- Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z
- ? diag::warn_cxx14_compat_decomp_decl
- : diag::ext_decomp_decl)
+ Diag(Decomp.getLSquareLoc(),
+ !getLangOpts().CPlusPlus17
+ ? diag::ext_decomp_decl
+ : D.getContext() == Declarator::ConditionContext
+ ? diag::ext_decomp_decl_cond
+ : diag::warn_cxx14_compat_decomp_decl)
<< Decomp.getSourceRange();
// The semantic context is always just the current context.
@@ -787,7 +794,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// Check for name conflicts.
DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
LookupName(Previous, S,
/*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
@@ -819,7 +826,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// is unnamed.
DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
Decomp.getLSquareLoc());
- LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ ForVisibleRedeclaration);
// Build the variable that holds the non-decomposed object.
bool AddToScope = true;
@@ -2151,7 +2159,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
return nullptr;
}
- if (EllipsisLoc.isValid() &&
+ if (EllipsisLoc.isValid() &&
!TInfo->getType()->containsUnexpandedParameterPack()) {
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< TInfo->getTypeLoc().getSourceRange();
@@ -2300,10 +2308,10 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
GetTypeFromParser(basetype, &TInfo);
if (EllipsisLoc.isInvalid() &&
- DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo,
+ DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo,
UPPC_BaseType))
return true;
-
+
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
Virtual, Access, TInfo,
EllipsisLoc))
@@ -2387,11 +2395,11 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
// Note this base's direct & indirect bases, if there could be ambiguity.
if (Bases.size() > 1)
NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType);
-
+
if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
if (Class->isInterface() &&
- (!RD->isInterface() ||
+ (!RD->isInterfaceLike() ||
KnownBase->getAccessSpecifier() != AS_public)) {
// The Microsoft extension __interface does not permit bases that
// are not themselves public interfaces.
@@ -2408,7 +2416,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
// Attach the remaining base class specifiers to the derived class.
Class->setBases(Bases.data(), NumGoodBases);
-
+
for (unsigned idx = 0; idx < NumGoodBases; ++idx) {
// Check whether this direct base is inaccessible due to ambiguity.
QualType BaseType = Bases[idx]->getType();
@@ -2460,7 +2468,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) {
CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
-
+
CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
@@ -2474,7 +2482,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) {
// to be able to use the inheritance relationship?
if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined())
return false;
-
+
return DerivedRD->isDerivedFrom(BaseRD);
}
@@ -2484,28 +2492,23 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base,
CXXBasePaths &Paths) {
if (!getLangOpts().CPlusPlus)
return false;
-
+
CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
-
+
CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
-
+
if (!isCompleteType(Loc, Derived) && !DerivedRD->isBeingDefined())
return false;
-
+
return DerivedRD->isDerivedFrom(BaseRD, Paths);
}
-void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
- CXXCastPath &BasePathArray) {
- assert(BasePathArray.empty() && "Base path array must be empty!");
- assert(Paths.isRecordingPaths() && "Must record paths!");
-
- const CXXBasePath &Path = Paths.front();
-
+static void BuildBasePathArray(const CXXBasePath &Path,
+ CXXCastPath &BasePathArray) {
// We first go backward and check if we have a virtual base.
// FIXME: It would be better if CXXBasePath had the base specifier for
// the nearest virtual base.
@@ -2522,6 +2525,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
BasePathArray.push_back(const_cast<CXXBaseSpecifier*>(Path[I].Base));
}
+
+void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXCastPath &BasePathArray) {
+ assert(BasePathArray.empty() && "Base path array must be empty!");
+ assert(Paths.isRecordingPaths() && "Must record paths!");
+ return ::BuildBasePathArray(Paths.front(), BasePathArray);
+}
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -2549,30 +2559,48 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
bool DerivationOkay = IsDerivedFrom(Loc, Derived, Base, Paths);
- assert(DerivationOkay &&
- "Can only be used with a derived-to-base conversion");
- (void)DerivationOkay;
-
- if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+ if (!DerivationOkay)
+ return true;
+
+ const CXXBasePath *Path = nullptr;
+ if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType()))
+ Path = &Paths.front();
+
+ // For MSVC compatibility, check if Derived directly inherits from Base. Clang
+ // warns about this hierarchy under -Winaccessible-base, but MSVC allows the
+ // user to access such bases.
+ if (!Path && getLangOpts().MSVCCompat) {
+ for (const CXXBasePath &PossiblePath : Paths) {
+ if (PossiblePath.size() == 1) {
+ Path = &PossiblePath;
+ if (AmbigiousBaseConvID)
+ Diag(Loc, diag::ext_ms_ambiguous_direct_base)
+ << Base << Derived << Range;
+ break;
+ }
+ }
+ }
+
+ if (Path) {
if (!IgnoreAccess) {
// Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
- InaccessibleBaseID)) {
- case AR_inaccessible:
- return true;
- case AR_accessible:
- case AR_dependent:
- case AR_delayed:
- break;
+ switch (
+ CheckBaseClassAccess(Loc, Base, Derived, *Path, InaccessibleBaseID)) {
+ case AR_inaccessible:
+ return true;
+ case AR_accessible:
+ case AR_dependent:
+ case AR_delayed:
+ break;
}
}
-
+
// Build a base path if necessary.
if (BasePath)
- BuildBasePathArray(Paths, *BasePath);
+ ::BuildBasePathArray(*Path, *BasePath);
return false;
}
-
+
if (AmbigiousBaseConvID) {
// We know that the derived-to-base conversion is ambiguous, and
// we're going to produce a diagnostic. Perform the derived-to-base
@@ -2637,7 +2665,7 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
PathDisplayStr += " -> " + Element->Base->getType().getAsString();
}
}
-
+
return PathDisplayStr;
}
@@ -2720,8 +2748,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
// If a function is marked with the virt-specifier override and
// does not override a member function of a base class, the program is
// ill-formed.
- bool HasOverriddenMethods =
- MD->begin_overridden_methods() != MD->end_overridden_methods();
+ bool HasOverriddenMethods = MD->size_overridden_methods() != 0;
if (MD->hasAttr<OverrideAttr>() && !HasOverriddenMethods)
Diag(MD->getLocation(), diag::err_function_marked_override_not_overriding)
<< MD->getDeclName();
@@ -2860,6 +2887,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert(!DS.isFriendSpecified());
bool isFunc = D.isDeclarationOfFunction();
+ AttributeList *MSPropertyAttr =
+ getMSPropertyAttr(D.getDeclSpec().getAttributes().getList());
if (cast<CXXRecordDecl>(CurContext)->isInterface()) {
// The Microsoft extension __interface only permits public member functions
@@ -2867,8 +2896,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// functions, static methods and data members.
unsigned InvalidDecl;
bool ShowDeclName = true;
- if (!isFunc)
- InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1;
+ if (!isFunc &&
+ (DS.getStorageClassSpec() == DeclSpec::SCS_typedef || MSPropertyAttr))
+ InvalidDecl = 0;
+ else if (!isFunc)
+ InvalidDecl = 1;
else if (AS != AS_public)
InvalidDecl = 2;
else if (DS.getStorageClassSpec() == DeclSpec::SCS_static)
@@ -3016,12 +3048,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
else
Diag(D.getIdentifierLoc(), diag::err_member_qualification)
<< Name << SS.getRange();
-
+
SS.clear();
}
- AttributeList *MSPropertyAttr =
- getMSPropertyAttr(D.getDeclSpec().getAttributes().getList());
if (MSPropertyAttr) {
Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D,
BitWidth, InitStyle, AS, MSPropertyAttr);
@@ -3390,14 +3420,9 @@ namespace {
void VisitCallExpr(CallExpr *E) {
// Treat std::move as a use.
- if (E->getNumArgs() == 1) {
- if (FunctionDecl *FD = E->getDirectCallee()) {
- if (FD->isInStdNamespace() && FD->getIdentifier() &&
- FD->getIdentifier()->isStr("move")) {
- HandleValue(E->getArg(0), false /*AddressOf*/);
- return;
- }
- }
+ if (E->isCallToStdMove()) {
+ HandleValue(E->getArg(0), /*AddressOf=*/false);
+ return;
}
Inherited::VisitCallExpr(E);
@@ -3585,7 +3610,7 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
/// \brief Find the direct and/or virtual base specifiers that
/// correspond to the given base type, for use in base initialization
/// within a constructor.
-static bool FindBaseInitializer(Sema &SemaRef,
+static bool FindBaseInitializer(Sema &SemaRef,
CXXRecordDecl *ClassDecl,
QualType BaseType,
const CXXBaseSpecifier *&DirectBaseSpec,
@@ -3769,7 +3794,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (SS.isSet() && isDependentScopeSpecifier(SS)) {
bool NotUnknownSpecialization = false;
DeclContext *DC = computeDeclContext(SS, false);
- if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC))
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC))
NotUnknownSpecialization = !Record->hasAnyDependentBases();
if (!NotUnknownSpecialization) {
@@ -3813,7 +3838,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
} else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
- if (FindBaseInitializer(*this, ClassDecl,
+ if (FindBaseInitializer(*this, ClassDecl,
Context.getTypeDeclType(Type),
DirectBaseSpec, VirtualBaseSpec)) {
// We have found a direct or virtual base class with a
@@ -4038,7 +4063,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
if (CurContext->isDependentContext())
DelegationInit = Init;
- return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
+ return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
DelegationInit.getAs<Expr>(),
InitRange.getEnd());
}
@@ -4083,12 +4108,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// Check for direct and virtual base classes.
const CXXBaseSpecifier *DirectBaseSpec = nullptr;
const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
- if (!Dependent) {
+ if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
- FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+ FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
// C++ [base.class.init]p2:
@@ -4208,7 +4233,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
IsInheritedVirtualBase);
ExprResult BaseInit;
-
+
switch (ImplicitInitKind) {
case IIK_Inherit:
case IIK_Default: {
@@ -4225,7 +4250,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
- Expr *CopyCtorArg =
+ Expr *CopyCtorArg =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param, false,
Constructor->getLocation(), ParamType,
@@ -4234,8 +4259,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg));
// Cast to the base class to avoid ambiguities.
- QualType ArgTy =
- SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
+ QualType ArgTy =
+ SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
ParamType.getQualifiers());
if (Moving) {
@@ -4261,10 +4286,10 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit);
if (BaseInit.isInvalid())
return true;
-
+
CXXBaseInit =
new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
- SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
+ SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
SourceLocation()),
BaseSpec->isVirtual(),
SourceLocation(),
@@ -4298,8 +4323,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Suppress copying zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
return false;
-
- Expr *MemberExprBase =
+
+ Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param, false,
Loc, ParamType, VK_LValue, nullptr);
@@ -4317,7 +4342,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect)
: cast<ValueDecl>(Field), AS_public);
MemberLookup.resolveKind();
- ExprResult CtorArg
+ ExprResult CtorArg
= SemaRef.BuildMemberReferenceExpr(MemberExprBase,
ParamType, Loc,
/*IsArrow=*/false,
@@ -4346,7 +4371,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// Direct-initialize to use the copy constructor.
InitializationKind InitKind =
InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
-
+
Expr *CtorArgE = CtorArg.getAs<Expr>();
InitializationSequence InitSeq(SemaRef, Entity, InitKind, CtorArgE);
ExprResult MemberInit =
@@ -4367,16 +4392,16 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) &&
"Unhandled implicit init kind!");
- QualType FieldBaseElementType =
+ QualType FieldBaseElementType =
SemaRef.Context.getBaseElementType(Field->getType());
-
+
if (FieldBaseElementType->isRecordType()) {
InitializedEntity InitEntity =
Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr,
/*Implicit*/ true)
: InitializedEntity::InitializeMember(Field, nullptr,
/*Implicit*/ true);
- InitializationKind InitKind =
+ InitializationKind InitKind =
InitializationKind::CreateDefault(Loc);
InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None);
@@ -4386,10 +4411,10 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
if (MemberInit.isInvalid())
return true;
-
+
if (Indirect)
CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context,
- Indirect, Loc,
+ Indirect, Loc,
Loc,
MemberInit.get(),
Loc);
@@ -4403,9 +4428,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
if (!Field->getParent()->isUnion()) {
if (FieldBaseElementType->isReferenceType()) {
- SemaRef.Diag(Constructor->getLocation(),
+ SemaRef.Diag(Constructor->getLocation(),
diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
+ << (int)Constructor->isImplicit()
<< SemaRef.Context.getTagDeclType(Constructor->getParent())
<< 0 << Field->getDeclName();
SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
@@ -4413,27 +4438,27 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
if (FieldBaseElementType.isConstQualified()) {
- SemaRef.Diag(Constructor->getLocation(),
+ SemaRef.Diag(Constructor->getLocation(),
diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
+ << (int)Constructor->isImplicit()
<< SemaRef.Context.getTagDeclType(Constructor->getParent())
<< 1 << Field->getDeclName();
SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
return true;
}
}
-
+
if (FieldBaseElementType.hasNonTrivialObjCLifetime()) {
// ARC and Weak:
// Default-initialize Objective-C pointers to NULL.
CXXMemberInit
- = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
- Loc, Loc,
- new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()),
+ = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ Loc, Loc,
+ new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()),
Loc);
return false;
}
-
+
// Nothing to initialize.
CXXMemberInit = nullptr;
return false;
@@ -4461,13 +4486,13 @@ struct BaseAndFieldInfo {
else
IIK = IIK_Default;
}
-
+
bool isImplicitCopyOrMove() const {
switch (IIK) {
case IIK_Copy:
case IIK_Move:
return true;
-
+
case IIK_Default:
case IIK_Inherit:
return false;
@@ -4534,19 +4559,19 @@ struct BaseAndFieldInfo {
static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
if (T->isIncompleteArrayType())
return true;
-
+
while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
if (!ArrayT->getSize())
return true;
-
+
T = ArrayT->getElementType();
}
-
+
return false;
}
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
- FieldDecl *Field,
+ FieldDecl *Field,
IndirectFieldDecl *Indirect = nullptr) {
if (Field->isInvalidDecl())
return false;
@@ -4659,7 +4684,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
if (!ClassDecl)
return true;
-
+
bool HadError = false;
for (unsigned i = 0; i < Initializers.size(); i++) {
@@ -4758,34 +4783,34 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// initialized.
if (F->isUnnamedBitfield())
continue;
-
+
// If we're not generating the implicit copy/move constructor, then we'll
// handle anonymous struct/union fields based on their individual
// indirect fields.
if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove())
continue;
-
+
if (CollectFieldInitializer(*this, Info, F))
HadError = true;
continue;
}
-
+
// Beyond this point, we only consider default initialization.
if (Info.isImplicitCopyOrMove())
continue;
-
+
if (auto *F = dyn_cast<IndirectFieldDecl>(Mem)) {
if (F->getType()->isIncompleteArrayType()) {
assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
continue;
}
-
+
// Initialize each field of an anonymous struct individually.
if (CollectFieldInitializer(*this, Info, F->getAnonField(), F))
HadError = true;
-
- continue;
+
+ continue;
}
}
@@ -4827,7 +4852,7 @@ static const void *GetKeyForMember(ASTContext &Context,
CXXCtorInitializer *Member) {
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
-
+
return Member->getAnyMember()->getCanonicalDecl();
}
@@ -4838,7 +4863,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
return;
// Don't check initializers order unless the warning is enabled at the
- // location of at least one initializer.
+ // location of at least one initializer.
bool ShouldCheckOrder = false;
for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
@@ -4850,7 +4875,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
}
if (!ShouldCheckOrder)
return;
-
+
// Build the list of bases and members in the order that they'll
// actually be initialized. The explicit initializers should be in
// this same order but may be missing things.
@@ -4873,10 +4898,10 @@ static void DiagnoseBaseOrMemInitializerOrder(
for (auto *Field : ClassDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
-
+
PopulateKeysForFields(Field, IdealInitKeys);
}
-
+
unsigned NumIdealInits = IdealInitKeys.size();
unsigned IdealIndex = 0;
@@ -4903,7 +4928,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
D << 0 << PrevInit->getAnyMember()->getDeclName();
else
D << 1 << PrevInit->getTypeSourceInfo()->getType();
-
+
if (Init->isAnyMemberInitializer())
D << 0 << Init->getAnyMember()->getDeclName();
else
@@ -4971,7 +4996,7 @@ bool CheckRedundantUnionInit(Sema &S,
S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
<< 0 << En.second->getSourceRange();
return true;
- }
+ }
if (!En.first) {
En.first = Child;
En.second = Init;
@@ -5005,7 +5030,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
return;
}
-
+
// Mapping for the duplicate initializers check.
// For member initializers, this is keyed with a FieldDecl*.
// For base initializers, this is keyed with a Type*.
@@ -5067,22 +5092,22 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// field/base declaration. That's probably good; that said, the
// user might reasonably want to know why the destructor is being
// emitted, and we currently don't say.
-
+
// Non-static data members.
for (auto *Field : ClassDecl->fields()) {
if (Field->isInvalidDecl())
continue;
-
+
// Don't destroy incomplete or zero-length arrays.
if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
continue;
QualType FieldType = Context.getBaseElementType(Field->getType());
-
+
const RecordType* RT = FieldType->getAs<RecordType>();
if (!RT)
continue;
-
+
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (FieldClassDecl->isInvalidDecl())
continue;
@@ -5137,14 +5162,14 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Base.getType()
<< Base.getSourceRange(),
Context.getTypeDeclType(ClassDecl));
-
+
MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
if (!VisitVirtualBases)
return;
-
+
// Virtual bases.
for (const auto &VBase : ClassDecl->vbases()) {
// Bases are always records in a well-formed non-dependent class.
@@ -5241,12 +5266,12 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
// Keep a set of seen pure methods so we won't diagnose the same method
// more than once.
llvm::SmallPtrSet<const CXXMethodDecl *, 8> SeenPureMethods;
-
- for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
MEnd = FinalOverriders.end();
- M != MEnd;
+ M != MEnd;
++M) {
- for (OverridingMethods::iterator SO = M->second.begin(),
+ for (OverridingMethods::iterator SO = M->second.begin(),
SOEnd = M->second.end();
SO != SOEnd; ++SO) {
// C++ [class.abstract]p4:
@@ -5254,7 +5279,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
// pure virtual function for which the final overrider is pure
// virtual.
- //
+ //
if (SO->second.size() != 1)
continue;
@@ -5264,8 +5289,8 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) {
if (!SeenPureMethods.insert(SO->second.front().Method).second)
continue;
- Diag(SO->second.front().Method->getLocation(),
- diag::note_pure_virtual_function)
+ Diag(SO->second.front().Method->getLocation(),
+ diag::note_pure_virtual_function)
<< SO->second.front().Method->getDeclName() << RD->getDeclName();
}
}
@@ -5745,7 +5770,7 @@ static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {
!D->defaultedCopyConstructorIsDeleted()) {
if (!D->hasTrivialCopyConstructor())
return false;
- HasNonDeletedCopyOrMove = true;
+ HasNonDeletedCopyOrMove = true;
}
if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() &&
@@ -5787,7 +5812,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
AbstractUsageInfo Info(*this, Record);
CheckAbstractClassUsage(Info, Record);
}
-
+
// If this is not an aggregate type and has no user-declared constructor,
// complain about any non-static data members of reference or const scalar
// type, since they will never get initializers.
@@ -5806,7 +5831,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
<< Record->getTagKind() << Record;
Complained = true;
}
-
+
Diag(F->getLocation(), diag::note_refconst_member_not_initialized)
<< F->getType()->isReferenceType()
<< F->getDeclName();
@@ -5816,12 +5841,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->getIdentifier()) {
// C++ [class.mem]p13:
- // If T is the name of a class, then each of the following shall have a
+ // If T is the name of a class, then each of the following shall have a
// name different from T:
// - every member of every anonymous union that is a member of class T.
//
// C++ [class.mem]p14:
- // In addition, if class T has a user-declared constructor (12.1), every
+ // In addition, if class T has a user-declared constructor (12.1), every
// non-static data member of class T shall have a name different from T.
DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
@@ -7398,10 +7423,8 @@ private:
const llvm::SmallPtrSetImpl<const CXXMethodDecl *> &Methods) {
if (MD->size_overridden_methods() == 0)
return Methods.count(MD->getCanonicalDecl());
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods();
- I != E; ++I)
- if (CheckMostOverridenMethods(*I, Methods))
+ for (const CXXMethodDecl *O : MD->overridden_methods())
+ if (CheckMostOverridenMethods(O, Methods))
return true;
return false;
}
@@ -7459,10 +7482,9 @@ static void AddMostOverridenMethods(const CXXMethodDecl *MD,
llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) {
if (MD->size_overridden_methods() == 0)
Methods.insert(MD->getCanonicalDecl());
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods();
- I != E; ++I)
- AddMostOverridenMethods(*I, Methods);
+ else
+ for (const CXXMethodDecl *O : MD->overridden_methods())
+ AddMostOverridenMethods(O, Methods);
}
/// \brief Check if a method overloads virtual methods in a base class without
@@ -7821,11 +7843,11 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
// A constructor shall not be declared with a ref-qualifier.
if (FTI.hasRefQualifier()) {
Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor)
- << FTI.RefQualifierIsLValueRef
+ << FTI.RefQualifierIsLValueRef
<< FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
D.setInvalidType();
}
-
+
// Rebuild the function type "R" without any type qualifiers (in
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types.
@@ -7864,8 +7886,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
QualType ClassTy = Context.getTagDeclType(ClassDecl);
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
- const char *ConstRef
- = Constructor->getParamDecl(0)->getIdentifier() ? "const &"
+ const char *ConstRef
+ = Constructor->getParamDecl(0)->getIdentifier() ? "const &"
: " const &";
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
<< FixItHint::CreateInsertion(ParamLoc, ConstRef);
@@ -7882,23 +7904,49 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
/// on error.
bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
CXXRecordDecl *RD = Destructor->getParent();
-
+
if (!Destructor->getOperatorDelete() && Destructor->isVirtual()) {
SourceLocation Loc;
-
+
if (!Destructor->isImplicit())
Loc = Destructor->getLocation();
else
Loc = RD->getLocation();
-
+
// If we have a virtual destructor, look up the deallocation function
if (FunctionDecl *OperatorDelete =
FindDeallocationFunctionForDestructor(Loc, RD)) {
+ Expr *ThisArg = nullptr;
+
+ // If the notional 'delete this' expression requires a non-trivial
+ // conversion from 'this' to the type of a destroying operator delete's
+ // first parameter, perform that conversion now.
+ if (OperatorDelete->isDestroyingOperatorDelete()) {
+ QualType ParamType = OperatorDelete->getParamDecl(0)->getType();
+ if (!declaresSameEntity(ParamType->getAsCXXRecordDecl(), RD)) {
+ // C++ [class.dtor]p13:
+ // ... as if for the expression 'delete this' appearing in a
+ // non-virtual destructor of the destructor's class.
+ ContextRAII SwitchContext(*this, Destructor);
+ ExprResult This =
+ ActOnCXXThis(OperatorDelete->getParamDecl(0)->getLocation());
+ assert(!This.isInvalid() && "couldn't form 'this' expr in dtor?");
+ This = PerformImplicitConversion(This.get(), ParamType, AA_Passing);
+ if (This.isInvalid()) {
+ // FIXME: Register this as a context note so that it comes out
+ // in the right order.
+ Diag(Loc, diag::note_implicit_delete_this_in_destructor_here);
+ return true;
+ }
+ ThisArg = This.get();
+ }
+ }
+
MarkFunctionReferenced(Loc, OperatorDelete);
- Destructor->setOperatorDelete(OperatorDelete);
+ Destructor->setOperatorDelete(OperatorDelete, ThisArg);
}
}
-
+
return false;
}
@@ -7939,7 +7987,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
<< "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
<< SourceRange(D.getIdentifierLoc())
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
-
+
SC = SC_None;
}
if (!D.isInvalidType()) {
@@ -7988,7 +8036,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
<< FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
D.setInvalidType();
}
-
+
// Make sure we don't have any parameters.
if (FTIHasNonVoidParameters(FTI)) {
Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
@@ -8007,7 +8055,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
// Rebuild the function type "R" without any type qualifiers or
// parameters (in case any of the errors above fired) and with
// "void" as the return type, since destructors don't have return
- // types.
+ // types.
if (!D.isInvalidType())
return R;
@@ -8236,7 +8284,7 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
return ConversionTemplate;
-
+
return Conversion;
}
@@ -8294,8 +8342,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.isConceptSpecified()) {
+ DS.isNoreturnSpecified() || DS.isConstexprSpecified()) {
BadSpecifierDiagnoser Diagnoser(
*this, D.getIdentifierLoc(),
diag::err_deduction_guide_invalid_specifier);
@@ -8308,9 +8355,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
Diagnoser.check(DS.getInlineSpecLoc(), "inline");
Diagnoser.check(DS.getNoreturnSpecLoc(), "_Noreturn");
Diagnoser.check(DS.getConstexprSpecLoc(), "constexpr");
- Diagnoser.check(DS.getConceptSpecLoc(), "concept");
DS.ClearConstexprSpec();
- DS.ClearConceptSpec();
Diagnoser.check(DS.getConstSpecLoc(), "const");
Diagnoser.check(DS.getRestrictSpecLoc(), "__restrict");
@@ -8464,7 +8509,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// Since namespace names are unique in their scope, and we don't
// look through using directives, just look for any ordinary names
// as if by qualified name lookup.
- LookupResult R(*this, II, IdentLoc, LookupOrdinaryName, ForRedeclaration);
+ LookupResult R(*this, II, IdentLoc, LookupOrdinaryName,
+ ForExternalRedeclaration);
LookupQualifiedName(R, CurContext->getRedeclContext());
NamedDecl *PrevDecl =
R.isSingleResult() ? R.getRepresentativeDecl() : nullptr;
@@ -8495,7 +8541,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
}
} else {
// Anonymous namespaces.
-
+
// Determine whether the parent already has an anonymous namespace.
DeclContext *Parent = CurContext->getRedeclContext();
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
@@ -8509,12 +8555,12 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II,
&IsInline, PrevNS);
}
-
+
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
StartLoc, Loc, II, PrevNS);
if (IsInvalid)
Namespc->setInvalidDecl();
-
+
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
AddPragmaAttributes(DeclRegionScope, Namespc);
@@ -8526,7 +8572,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
StdNamespace = Namespc;
if (AddToKnown)
KnownNamespaces[Namespc] = false;
-
+
if (II) {
PushOnScopeChains(Namespc, DeclRegionScope);
} else {
@@ -8627,12 +8673,12 @@ NamespaceDecl *Sema::lookupStdExperimentalNamespace() {
return StdExperimentalNamespaceCache;
}
-/// \brief Retrieve the special "std" namespace, which may require us to
+/// \brief Retrieve the special "std" namespace, which may require us to
/// implicitly define the namespace.
NamespaceDecl *Sema::getOrCreateStdNamespace() {
if (!StdNamespace) {
// The "std" namespace has not yet been defined, so build one implicitly.
- StdNamespace = NamespaceDecl::Create(Context,
+ StdNamespace = NamespaceDecl::Create(Context,
Context.getTranslationUnitDecl(),
/*Inline=*/false,
SourceLocation(), SourceLocation(),
@@ -8845,7 +8891,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
NestedNameSpecifier *Qualifier = nullptr;
if (SS.isSet())
Qualifier = SS.getScopeRep();
-
+
// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS);
@@ -8854,18 +8900,18 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
if (R.empty()) {
R.clear();
- // Allow "using namespace std;" or "using namespace ::std;" even if
+ // Allow "using namespace std;" or "using namespace ::std;" even if
// "std" hasn't been defined yet, for GCC compatibility.
if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) &&
NamespcName->isStr("std")) {
Diag(IdentLoc, diag::ext_using_undefined_std);
R.addDecl(getOrCreateStdNamespace());
R.resolveKind();
- }
+ }
// Otherwise, attempt typo correction.
else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName);
}
-
+
if (!R.empty()) {
NamedDecl *Named = R.getRepresentativeDecl();
NamespaceDecl *NS = R.getAsSingle<NamespaceDecl>();
@@ -8946,7 +8992,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_ConversionFunctionId:
break;
-
+
case UnqualifiedId::IK_ConstructorName:
case UnqualifiedId::IK_ConstructorTemplateId:
// C++11 inheriting constructors.
@@ -9089,7 +9135,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// If the target happens to be one of the previous declarations, we
// don't have a conflict.
- //
+ //
// FIXME: but we might be increasing its access, in which case we
// should redeclare it.
NamedDecl *NonTag = nullptr, *Tag = nullptr;
@@ -9401,7 +9447,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Do the redeclaration lookup in the current scope.
LookupResult Previous(*this, UsingName, LookupUsingDeclName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
Previous.setHideTags(false);
if (S) {
LookupName(Previous, S);
@@ -9464,7 +9510,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
IdentLoc, NameInfo.getName(),
EllipsisLoc);
} else {
- D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
+ D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
QualifierLoc, NameInfo, EllipsisLoc);
}
D->setAccess(AS);
@@ -9977,11 +10023,14 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
UPPC_DeclarationType)) {
Invalid = true;
- TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
+ TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
TInfo->getTypeLoc().getBeginLoc());
}
- LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ TemplateParamLists.size()
+ ? forRedeclarationInCurContext()
+ : ForVisibleRedeclaration);
LookupName(Previous, S);
// Warn about shadowing the name of a template parameter.
@@ -10084,8 +10133,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewDecl->setInvalidDecl();
- else if (OldDecl)
+ else if (OldDecl) {
NewDecl->setPreviousDecl(OldDecl);
+ CheckRedeclarationModuleOwnership(NewDecl, OldDecl);
+ }
NewND = NewDecl;
} else {
@@ -10126,7 +10177,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
// Check if we have a previous declaration with the same name.
LookupResult PrevR(*this, Alias, AliasLoc, LookupOrdinaryName,
- ForRedeclaration);
+ ForVisibleRedeclaration);
LookupName(PrevR, S);
// Check we're not shadowing a template parameter.
@@ -10140,7 +10191,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
/*AllowInlineNamespace*/false);
// Find the previous declaration and check that we can redeclare it.
- NamespaceAliasDecl *Prev = nullptr;
+ NamespaceAliasDecl *Prev = nullptr;
if (PrevR.isSingleResult()) {
NamedDecl *PrevDecl = PrevR.getRepresentativeDecl();
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
@@ -10261,7 +10312,7 @@ ComputeDefaultedSpecialMemberExceptionSpec(
CXXRecordDecl *ClassDecl = MD->getParent();
// C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
+ // An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc);
if (ClassDecl->isInvalidDecl())
@@ -10339,7 +10390,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
// implicit special members with this name.
DeclarationName Name = FD->getDeclName();
LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName,
- ForRedeclaration);
+ ForExternalRedeclaration);
for (auto *D : FD->getParent()->lookup(Name))
if (auto *Acceptable = R.getAcceptableDecl(D))
R.addDecl(Acceptable);
@@ -11126,7 +11177,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
//
// for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
//
- // that will copy each of the array elements.
+ // that will copy each of the array elements.
QualType SizeType = S.Context.getSizeType();
// Create the iteration variable.
@@ -11338,7 +11389,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *CopyAssignOperator) {
- assert((CopyAssignOperator->isDefaulted() &&
+ assert((CopyAssignOperator->isDefaulted() &&
CopyAssignOperator->isOverloadedOperator() &&
CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
!CopyAssignOperator->doesThisDeclarationHaveABody() &&
@@ -11372,15 +11423,15 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// C++0x [class.copy]p30:
// The implicitly-defined or explicitly-defaulted copy assignment operator
- // for a non-union class X performs memberwise copy assignment of its
- // subobjects. The direct base classes of X are assigned first, in the
- // order of their declaration in the base-specifier-list, and then the
- // immediate non-static data members of X are assigned, in the order in
+ // for a non-union class X performs memberwise copy assignment of its
+ // subobjects. The direct base classes of X are assigned first, in the
+ // order of their declaration in the base-specifier-list, and then the
+ // immediate non-static data members of X are assigned, in the order in
// which they were declared in the class definition.
-
+
// The statements that form the synthesized function body.
SmallVector<Stmt*, 8> Statements;
-
+
// The parameter for the "other" object, which we are copying from.
ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
Qualifiers OtherQuals = Other->getType().getQualifiers();
@@ -11390,7 +11441,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
OtherRefType = OtherRef->getPointeeType();
OtherQuals = OtherRefType.getQualifiers();
}
-
+
// Our location for everything implicitly-generated.
SourceLocation Loc = CopyAssignOperator->getLocEnd().isValid()
? CopyAssignOperator->getLocEnd()
@@ -11401,7 +11452,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Builds the "this" pointer.
ThisBuilder This;
-
+
// Assign base classes.
bool Invalid = false;
for (auto &Base : ClassDecl->bases()) {
@@ -11437,11 +11488,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setInvalidDecl();
return;
}
-
+
// Success! Record the copy.
Statements.push_back(Copy.getAs<Expr>());
}
-
+
// Assign non-static members.
for (auto *Field : ClassDecl->fields()) {
// FIXME: We should form some kind of AST representation for the implied
@@ -11462,28 +11513,28 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Invalid = true;
continue;
}
-
+
// Check for members of const-qualified, non-class type.
QualType BaseType = Context.getBaseElementType(Field->getType());
if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Invalid = true;
+ Invalid = true;
continue;
}
// Suppress assigning zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
continue;
-
+
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
- assert(ClassDecl->hasFlexibleArrayMember() &&
+ assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
continue;
}
-
+
// Build references to the field in the object we're copying from and to.
CXXScopeSpec SS; // Intentionally empty
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
@@ -11504,7 +11555,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CopyAssignOperator->setInvalidDecl();
return;
}
-
+
// Success! Record the copy.
Statements.push_back(Copy.getAs<Stmt>());
}
@@ -11512,7 +11563,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
-
+
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
@@ -11700,7 +11751,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *MoveAssignOperator) {
- assert((MoveAssignOperator->isDefaulted() &&
+ assert((MoveAssignOperator->isDefaulted() &&
MoveAssignOperator->isOverloadedOperator() &&
MoveAssignOperator->getOverloadedOperator() == OO_Equal &&
!MoveAssignOperator->doesThisDeclarationHaveABody() &&
@@ -11714,7 +11765,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MoveAssignOperator->setInvalidDecl();
return;
}
-
+
// C++0x [class.copy]p28:
// The implicitly-defined or move assignment operator for a non-union class
// X performs memberwise move assignment of its subobjects. The direct base
@@ -11836,21 +11887,21 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Invalid = true;
+ Invalid = true;
continue;
}
// Suppress assigning zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
continue;
-
+
QualType FieldType = Field->getType().getNonReferenceType();
if (FieldType->isIncompleteArrayType()) {
- assert(ClassDecl->hasFlexibleArrayMember() &&
+ assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
continue;
}
-
+
// Build references to the field in the object we're copying from and to.
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
LookupMemberName);
@@ -12164,26 +12215,26 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv) {
SynthesizedFunctionScope Scope(*this, Conv);
-
+
CXXRecordDecl *Lambda = Conv->getParent();
CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
// If we are defining a specialization of a conversion to function-ptr
// cache the deduced template arguments for this specialization
// so that we can use them to retrieve the corresponding call-operator
- // and static-invoker.
+ // and static-invoker.
const TemplateArgumentList *DeducedTemplateArgs = nullptr;
// Retrieve the corresponding call-operator specialization.
if (Lambda->isGenericLambda()) {
assert(Conv->isFunctionTemplateSpecialization());
- FunctionTemplateDecl *CallOpTemplate =
+ FunctionTemplateDecl *CallOpTemplate =
CallOp->getDescribedFunctionTemplate();
DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
void *InsertPos = nullptr;
FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
DeducedTemplateArgs->asArray(),
InsertPos);
- assert(CallOpSpec &&
+ assert(CallOpSpec &&
"Conversion operator must have a corresponding call operator");
CallOp = cast<CXXMethodDecl>(CallOpSpec);
}
@@ -12199,15 +12250,15 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
// ... and get the corresponding specialization for a generic lambda.
if (Lambda->isGenericLambda()) {
- assert(DeducedTemplateArgs &&
+ assert(DeducedTemplateArgs &&
"Must have deduced template arguments from Conversion Operator");
- FunctionTemplateDecl *InvokeTemplate =
+ FunctionTemplateDecl *InvokeTemplate =
Invoker->getDescribedFunctionTemplate();
void *InsertPos = nullptr;
FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
DeducedTemplateArgs->asArray(),
InsertPos);
- assert(InvokeSpec &&
+ assert(InvokeSpec &&
"Must have a corresponding static invoker specialization");
Invoker = cast<CXXMethodDecl>(InvokeSpec);
}
@@ -12222,13 +12273,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
Conv->markUsed(Context);
Conv->setReferenced();
-
+
// Fill in the __invoke function with a dummy implementation. IR generation
// will fill in the actual details.
Invoker->markUsed(Context);
Invoker->setReferenced();
Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
-
+
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
L->CompletedImplicitDefinition(Invoker);
@@ -12239,16 +12290,16 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
+ CXXConversionDecl *Conv)
{
assert(!Conv->getParent()->isGenericLambda());
SynthesizedFunctionScope Scope(*this, Conv);
-
+
// Copy-initialize the lambda object as needed to capture it.
Expr *This = ActOnCXXThis(CurrentLocation).get();
Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).get();
-
+
ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation,
Conv->getLocation(),
Conv, DerefThis);
@@ -12283,29 +12334,29 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
Conv->getLocation(),
Conv->getLocation()));
Conv->markUsed(Context);
-
+
// We're done; notify the mutation listener, if any.
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
}
}
-/// \brief Determine whether the given list arguments contains exactly one
+/// \brief Determine whether the given list arguments contains exactly one
/// "real" (non-default) argument.
static bool hasOneRealArgument(MultiExprArg Args) {
switch (Args.size()) {
case 0:
return false;
-
+
default:
if (!Args[1]->isDefaultArgument())
return false;
-
+
// fall through
case 1:
return !Args[0]->isDefaultArgument();
}
-
+
return false;
}
@@ -12362,7 +12413,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
if (DiagnoseUseOfDecl(Constructor, ConstructLoc))
- return ExprError();
+ return ExprError();
}
return BuildCXXConstructExpr(
@@ -12439,7 +12490,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
assert(Pattern && "We must have set the Pattern!");
}
- if (InstantiateInClassInitializer(Loc, Field, Pattern,
+ if (!Pattern->hasInClassInitializer() ||
+ InstantiateInClassInitializer(Loc, Field, Pattern,
getTemplateInstantiationArgs(Field))) {
// Don't diagnose this again.
Field->setInvalidDecl();
@@ -12505,7 +12557,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
/// to form a proper call to this constructor.
///
/// \returns true if an error occurred, false otherwise.
-bool
+bool
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
@@ -12516,7 +12568,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
unsigned NumArgs = ArgsPtr.size();
Expr **Args = ArgsPtr.data();
- const FunctionProtoType *Proto
+ const FunctionProtoType *Proto
= Constructor->getType()->getAs<FunctionProtoType>();
assert(Proto && "Constructor without a prototype?");
unsigned NumParams = Proto->getNumParams();
@@ -12527,7 +12579,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
else
ConvertedArgs.reserve(NumArgs);
- VariadicCallType CallType =
+ VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
@@ -12548,22 +12600,22 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
}
static inline bool
-CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
+CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
const FunctionDecl *FnDecl) {
const DeclContext *DC = FnDecl->getDeclContext()->getRedeclContext();
if (isa<NamespaceDecl>(DC)) {
- return SemaRef.Diag(FnDecl->getLocation(),
+ return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_declared_in_namespace)
<< FnDecl->getDeclName();
}
-
- if (isa<TranslationUnitDecl>(DC) &&
+
+ if (isa<TranslationUnitDecl>(DC) &&
FnDecl->getStorageClass() == SC_Static) {
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_declared_static)
<< FnDecl->getDeclName();
}
-
+
return false;
}
@@ -12585,21 +12637,21 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
// Check that the result type is what we expect.
if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
return SemaRef.Diag(FnDecl->getLocation(),
- diag::err_operator_new_delete_invalid_result_type)
+ diag::err_operator_new_delete_invalid_result_type)
<< FnDecl->getDeclName() << ExpectedResultType;
-
+
// A function template must have at least 2 parameters.
if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_template_too_few_parameters)
<< FnDecl->getDeclName();
-
+
// The function decl must have at least 1 parameter.
if (FnDecl->getNumParams() == 0)
return SemaRef.Diag(FnDecl->getLocation(),
diag::err_operator_new_delete_too_few_parameters)
<< FnDecl->getDeclName();
-
+
// Check the first parameter type is not dependent.
QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
if (FirstParamType->isDependentType())
@@ -12607,11 +12659,11 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
<< FnDecl->getDeclName() << ExpectedFirstParamType;
// Check that the first parameter type is what we expect.
- if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
+ if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
ExpectedFirstParamType)
return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
<< FnDecl->getDeclName() << ExpectedFirstParamType;
-
+
return false;
}
@@ -12619,18 +12671,18 @@ static bool
CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
// C++ [basic.stc.dynamic.allocation]p1:
// A program is ill-formed if an allocation function is declared in a
- // namespace scope other than global scope or declared static in global
+ // namespace scope other than global scope or declared static in global
// scope.
if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
return true;
- CanQualType SizeTy =
+ CanQualType SizeTy =
SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType());
// C++ [basic.stc.dynamic.allocation]p1:
- // The return type shall be void*. The first parameter shall have type
+ // The return type shall be void*. The first parameter shall have type
// std::size_t.
- if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy,
+ if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy,
SizeTy,
diag::err_operator_new_dependent_param_type,
diag::err_operator_new_param_type))
@@ -12650,19 +12702,39 @@ static bool
CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
// C++ [basic.stc.dynamic.deallocation]p1:
// A program is ill-formed if deallocation functions are declared in a
- // namespace scope other than global scope or declared static in global
+ // namespace scope other than global scope or declared static in global
// scope.
if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl))
return true;
+ auto *MD = dyn_cast<CXXMethodDecl>(FnDecl);
+
+ // C++ P0722:
+ // Within a class C, the first parameter of a destroying operator delete
+ // shall be of type C *. The first parameter of any other deallocation
+ // function shall be of type void *.
+ CanQualType ExpectedFirstParamType =
+ MD && MD->isDestroyingOperatorDelete()
+ ? SemaRef.Context.getCanonicalType(SemaRef.Context.getPointerType(
+ SemaRef.Context.getRecordType(MD->getParent())))
+ : SemaRef.Context.VoidPtrTy;
+
// C++ [basic.stc.dynamic.deallocation]p2:
- // Each deallocation function shall return void and its first parameter
- // shall be void*.
- if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy,
- SemaRef.Context.VoidPtrTy,
- diag::err_operator_delete_dependent_param_type,
- diag::err_operator_delete_param_type))
+ // Each deallocation function shall return void
+ if (CheckOperatorNewDeleteTypes(
+ SemaRef, FnDecl, SemaRef.Context.VoidTy, ExpectedFirstParamType,
+ diag::err_operator_delete_dependent_param_type,
+ diag::err_operator_delete_param_type))
+ return true;
+
+ // C++ P0722:
+ // A destroying operator delete shall be a usual deallocation function.
+ if (MD && !MD->getParent()->isDependentContext() &&
+ MD->isDestroyingOperatorDelete() && !MD->isUsualDeallocationFunction()) {
+ SemaRef.Diag(MD->getLocation(),
+ diag::err_destroying_operator_delete_not_usual);
return true;
+ }
return false;
}
@@ -12684,7 +12756,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// explicitly stated in 3.7.3.
if (Op == OO_Delete || Op == OO_Array_Delete)
return CheckOperatorDeleteDeclaration(*this, FnDecl);
-
+
if (Op == OO_New || Op == OO_Array_New)
return CheckOperatorNewDeclaration(*this, FnDecl);
@@ -13000,7 +13072,8 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
StringRef LiteralName
= FnDecl->getDeclName().getCXXLiteralIdentifier()->getName();
- if (LiteralName[0] != '_') {
+ if (LiteralName[0] != '_' &&
+ !getSourceManager().isInSystemHeader(FnDecl->getLocation())) {
// C++11 [usrlit.suffix]p1:
// Literal suffix identifiers that do not start with an underscore
// are reserved for future standardization.
@@ -13087,7 +13160,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
IdentifierInfo *Name) {
bool Invalid = false;
QualType ExDeclType = TInfo->getType();
-
+
// Arrays and functions decay.
if (ExDeclType->isArrayType())
ExDeclType = Context.getArrayDecayedType(ExDeclType);
@@ -13151,7 +13224,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name,
ExDeclType, TInfo, SC_None);
ExDecl->setExceptionVariable(true);
-
+
// In ARC, infer 'retaining' for variables of retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(ExDecl))
Invalid = true;
@@ -13192,13 +13265,13 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Expr *init = MaybeCreateExprWithCleanups(construct);
ExDecl->setInit(init);
}
-
+
// And make sure it's destructable.
FinalizeVarWithDestructor(ExDecl, recordType);
}
}
}
-
+
if (Invalid)
ExDecl->setInvalidDecl();
@@ -13214,7 +13287,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
UPPC_ExceptionType)) {
- TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
+ TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
D.getIdentifierLoc());
Invalid = true;
}
@@ -13222,7 +13295,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
IdentifierInfo *II = D.getIdentifier();
if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(),
LookupOrdinaryName,
- ForRedeclaration)) {
+ ForVisibleRedeclaration)) {
// The scope should be freshly made just for us. There is just no way
// it contains any previous declaration, except for function parameters in
// a function-try-block's catch statement.
@@ -13299,8 +13372,20 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
llvm::raw_svector_ostream Msg(MsgBuffer);
if (AssertMessage)
AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy());
- Diag(StaticAssertLoc, diag::err_static_assert_failed)
- << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+
+ Expr *InnerCond = nullptr;
+ std::string InnerCondDescription;
+ std::tie(InnerCond, InnerCondDescription) =
+ findFailedBooleanCondition(Converted.get(),
+ /*AllowTopLevelCond=*/false);
+ if (InnerCond) {
+ Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
+ << InnerCondDescription << !AssertMessage
+ << Msg.str() << InnerCond->getSourceRange();
+ } else {
+ Diag(StaticAssertLoc, diag::err_static_assert_failed)
+ << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+ }
Failed = true;
}
}
@@ -13328,10 +13413,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo) {
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
-
+
QualType T = TSInfo->getType();
SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
-
+
// C++03 [class.friend]p2:
// An elaborated-type-specifier shall be used in a friend declaration
// for a class.*
@@ -13375,7 +13460,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
<< T
<< TypeRange;
}
-
+
// C++11 [class.friend]p3:
// A friend declaration that does not declare a function shall have one
// of the following forms:
@@ -13488,9 +13573,9 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
CurContext->addDecl(Friend);
return Friend;
}
-
+
assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?");
-
+
// Handle the case of a templated-scope friend class. e.g.
@@ -13570,7 +13655,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< DS.getSourceRange();
return nullptr;
}
-
+
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
// This is fixed in DR77, which just barely didn't make the C++03
@@ -13590,7 +13675,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
DS.getFriendSpecLoc());
else
D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI);
-
+
if (!D)
return nullptr;
@@ -13659,7 +13744,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
DeclContext *DC;
Scope *DCScope = S;
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
+ ForExternalRedeclaration);
// There are five cases here.
// - There's no scope specifier and we're in a local class. Only look
@@ -13790,15 +13875,15 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_is_member :
diag::err_friend_is_member);
-
+
if (D.isFunctionDefinition()) {
// C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
+ // A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
SemaDiagnosticBuilder DB
= Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def);
-
+
DB << SS.getScopeRep();
if (DC->isFileContext())
DB << FixItHint::CreateRemoval(SS.getRange());
@@ -13813,13 +13898,13 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
} else {
if (D.isFunctionDefinition()) {
// C++ [class.friend]p6:
- // A function can be defined in a friend declaration of a class if and
+ // A function can be defined in a friend declaration of a class if and
// only if the class is a non-local class (9.8), the function name is
// unqualified, and the function has namespace scope.
Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def)
<< SS.getScopeRep();
}
-
+
DC = CurContext;
assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?");
}
@@ -13855,7 +13940,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
}
// FIXME: This is an egregious hack to cope with cases where the scope stack
- // does not contain the declaration context, i.e., in an out-of-line
+ // does not contain the declaration context, i.e., in an out-of-line
// definition of a class.
Scope FakeDCScope(S, Scope::DeclScope, Diags);
if (!DCScope) {
@@ -13973,15 +14058,13 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// non-deleted virtual function.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
bool IssuedDiagnostic = false;
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods();
- I != E; ++I) {
+ for (const CXXMethodDecl *O : MD->overridden_methods()) {
if (!(*MD->begin_overridden_methods())->isDeleted()) {
if (!IssuedDiagnostic) {
Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName();
IssuedDiagnostic = true;
}
- Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+ Diag(O->getLocation(), diag::note_overridden_virtual_function);
}
}
// If this function was implicitly deleted because it was defaulted,
@@ -14071,8 +14154,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- const FunctionType *NewFT = New->getType()->getAs<FunctionType>();
- const FunctionType *OldFT = Old->getType()->getAs<FunctionType>();
+ const auto *NewFT = New->getType()->getAs<FunctionProtoType>();
+ const auto *OldFT = Old->getType()->getAs<FunctionProtoType>();
+
+ if (OldFT->hasExtParameterInfos()) {
+ for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I)
+ // A parameter of the overriding method should be annotated with noescape
+ // if the corresponding parameter of the overridden method is annotated.
+ if (OldFT->getExtParameterInfo(I).isNoEscape() &&
+ !NewFT->getExtParameterInfo(I).isNoEscape()) {
+ Diag(New->getParamDecl(I)->getLocation(),
+ diag::warn_overriding_method_missing_noescape);
+ Diag(Old->getParamDecl(I)->getLocation(),
+ diag::note_overridden_marked_noescape);
+ }
+ }
CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();
@@ -14230,21 +14326,22 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
Diag(D->getLocation(), diag::err_illegal_initializer);
}
-/// \brief Determine whether the given declaration is a static data member.
-static bool isStaticDataMember(const Decl *D) {
+/// \brief Determine whether the given declaration is a global variable or
+/// static data member.
+static bool isNonlocalVariable(const Decl *D) {
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
- return Var->isStaticDataMember();
+ return Var->hasGlobalStorage();
return false;
}
-/// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse
-/// an initializer for the out-of-line declaration 'Dcl'. The scope
-/// is a fresh scope pushed for just this purpose.
+/// Invoked when we are about to parse an initializer for the declaration
+/// 'Dcl'.
///
/// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a
/// static data member of class X, names should be looked up in the scope of
-/// class X.
+/// class X. If the declaration had a scope specifier, a scope will have
+/// been created and passed in for this purpose. Otherwise, S will be null.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
@@ -14254,28 +14351,27 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// might not be out of line if the specifier names the current namespace:
// extern int n;
// int ::n = 0;
- if (D->isOutOfLine())
+ if (S && D->isOutOfLine())
EnterDeclaratorContext(S, D->getDeclContext());
// If we are parsing the initializer for a static data member, push a
// new expression evaluation context that is associated with this static
// data member.
- if (isStaticDataMember(D))
+ if (isNonlocalVariable(D))
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated, D);
}
-/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
-/// initializer for the out-of-line declaration 'D'.
+/// Invoked after we are finished parsing an initializer for the declaration D.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
return;
- if (isStaticDataMember(D))
+ if (isNonlocalVariable(D))
PopExpressionEvaluationContext();
- if (D->isOutOfLine())
+ if (S && D->isOutOfLine())
ExitDeclaratorContext(S);
}
@@ -14306,7 +14402,7 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
void Sema::LoadExternalVTableUses() {
if (!ExternalSource)
return;
-
+
SmallVector<ExternalVTableUse, 4> VTables;
ExternalSource->ReadUsedVTables(VTables);
SmallVector<VTableUse, 4> NewUses;
@@ -14319,11 +14415,11 @@ void Sema::LoadExternalVTableUses() {
Pos->second = true;
continue;
}
-
+
VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired;
NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location));
}
-
+
VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end());
}
@@ -14530,17 +14626,17 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
FieldDecl *Field = ivars[i];
if (Field->isInvalidDecl())
continue;
-
+
CXXCtorInitializer *Member;
InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
- InitializationKind InitKind =
+ InitializationKind InitKind =
InitializationKind::CreateDefault(ObjCImplementation->getLocation());
InitializationSequence InitSeq(*this, InitEntity, InitKind, None);
ExprResult MemberInit =
InitSeq.Perform(*this, InitEntity, InitKind, None);
MemberInit = MaybeCreateExprWithCleanups(MemberInit);
- // Note, MemberInit could actually come back empty if no initialization
+ // Note, MemberInit could actually come back empty if no initialization
// is required (e.g., because it would call a trivial default constructor)
if (!MemberInit.get() || MemberInit.isInvalid())
continue;
@@ -14551,7 +14647,7 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
MemberInit.getAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
-
+
// Be sure that the destructor is accessible and is marked as referenced.
if (const RecordType *RecordTy =
Context.getBaseElementType(Field->getType())
@@ -14563,9 +14659,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
PDiag(diag::err_access_dtor_ivar)
<< Context.getBaseElementType(Field->getType()));
}
- }
+ }
}
- ObjCImplementation->setIvarInitializers(Context,
+ ObjCImplementation->setIvarInitializers(Context,
AllToInit.data(), AllToInit.size());
}
}
@@ -14633,7 +14729,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
DelegatingCycleHelper(Target, Valid, Invalid, Current, S);
}
}
-
+
void Sema::CheckDelegatingCtorCycles() {
llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
@@ -14654,10 +14750,10 @@ namespace {
/// \brief AST visitor that finds references to the 'this' expression.
class FindCXXThisExpr : public RecursiveASTVisitor<FindCXXThisExpr> {
Sema &S;
-
+
public:
explicit FindCXXThisExpr(Sema &S) : S(S) { }
-
+
bool VisitCXXThisExpr(CXXThisExpr *E) {
S.Diag(E->getLocation(), diag::err_this_static_member_func)
<< E->isImplicit();
@@ -14670,22 +14766,22 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
TypeSourceInfo *TSInfo = Method->getTypeSourceInfo();
if (!TSInfo)
return false;
-
+
TypeLoc TL = TSInfo->getTypeLoc();
FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
-
+
// C++11 [expr.prim.general]p3:
- // [The expression this] shall not appear before the optional
- // cv-qualifier-seq and it shall not appear within the declaration of a
+ // [The expression this] shall not appear before the optional
+ // cv-qualifier-seq and it shall not appear within the declaration of a
// static member function (although its type and value category are defined
// within a static member function as they are within a non-static member
// function). [ Note: this is because declaration matching does not occur
// until the complete declarator is known. - end note ]
const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
-
+
// If the return type came after the cv-qualifier-seq, check it now.
if (Proto->hasTrailingReturn() &&
!Finder.TraverseTypeLoc(ProtoTL.getReturnLoc()))
@@ -14694,7 +14790,7 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
// Check the exception specification.
if (checkThisInStaticMemberFunctionExceptionSpec(Method))
return true;
-
+
return checkThisInStaticMemberFunctionAttributes(Method);
}
@@ -14702,12 +14798,12 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
TypeSourceInfo *TSInfo = Method->getTypeSourceInfo();
if (!TSInfo)
return false;
-
+
TypeLoc TL = TSInfo->getTypeLoc();
FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
-
+
const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
@@ -14720,12 +14816,12 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
case EST_MSAny:
case EST_None:
break;
-
+
case EST_ComputedNoexcept:
if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
return true;
LLVM_FALLTHROUGH;
-
+
case EST_Dynamic:
for (const auto &E : Proto->exceptions()) {
if (!Finder.TraverseType(E))
@@ -14774,13 +14870,13 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
if (Arg && !Finder.TraverseStmt(Arg))
return true;
-
+
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
if (!Finder.TraverseStmt(Args[I]))
return true;
}
}
-
+
return false;
}
@@ -14831,10 +14927,16 @@ void Sema::checkExceptionSpecification(
return;
}
- if (!NoexceptExpr->isValueDependent())
- NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, nullptr,
- diag::err_noexcept_needs_constant_expression,
- /*AllowFold*/ false).get();
+ if (!NoexceptExpr->isValueDependent()) {
+ ExprResult Result = VerifyIntegerConstantExpression(
+ NoexceptExpr, nullptr, diag::err_noexcept_needs_constant_expression,
+ /*AllowFold*/ false);
+ if (Result.isInvalid()) {
+ ESI.Type = EST_BasicNoexcept;
+ return;
+ }
+ NoexceptExpr = Result.get();
+ }
ESI.NoexceptExpr = NoexceptExpr;
}
return;
@@ -14873,10 +14975,8 @@ void Sema::actOnDelayedExceptionSpecification(Decl *MethodD,
if (Method->isVirtual()) {
// Check overrides, which we previously had to delay.
- for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(),
- OEnd = Method->end_overridden_methods();
- O != OEnd; ++O)
- CheckOverridingFunctionExceptionSpec(Method, *O);
+ for (const CXXMethodDecl *O : Method->overridden_methods())
+ CheckOverridingFunctionExceptionSpec(Method, O);
}
}
@@ -14912,7 +15012,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
- << getLangOpts().CPlusPlus1z;
+ << getLangOpts().CPlusPlus17;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)
@@ -14920,7 +15020,8 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = nullptr;
- LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
+ LookupResult Previous(*this, II, Loc, LookupMemberName,
+ ForVisibleRedeclaration);
LookupName(Previous, S);
switch (Previous.getResultKind()) {
case LookupResult::Found:
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 967573011d0d..abbdc9574b8c 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -157,34 +157,44 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
diag::note_related_result_type_overridden);
}
if (getLangOpts().ObjCAutoRefCount) {
- if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() !=
- Overridden->hasAttr<NSReturnsRetainedAttr>())) {
- Diag(NewMethod->getLocation(),
- diag::err_nsreturns_retained_attribute_mismatch) << 1;
- Diag(Overridden->getLocation(), diag::note_previous_decl)
- << "method";
+ Diags.setSeverity(diag::warn_nsreturns_retained_attribute_mismatch,
+ diag::Severity::Error, SourceLocation());
+ Diags.setSeverity(diag::warn_nsconsumed_attribute_mismatch,
+ diag::Severity::Error, SourceLocation());
+ }
+
+ if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() !=
+ Overridden->hasAttr<NSReturnsRetainedAttr>())) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_nsreturns_retained_attribute_mismatch) << 1;
+ Diag(Overridden->getLocation(), diag::note_previous_decl) << "method";
+ }
+ if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() !=
+ Overridden->hasAttr<NSReturnsNotRetainedAttr>())) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_nsreturns_retained_attribute_mismatch) << 0;
+ Diag(Overridden->getLocation(), diag::note_previous_decl) << "method";
+ }
+
+ ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(),
+ oe = Overridden->param_end();
+ for (ObjCMethodDecl::param_iterator ni = NewMethod->param_begin(),
+ ne = NewMethod->param_end();
+ ni != ne && oi != oe; ++ni, ++oi) {
+ const ParmVarDecl *oldDecl = (*oi);
+ ParmVarDecl *newDecl = (*ni);
+ if (newDecl->hasAttr<NSConsumedAttr>() !=
+ oldDecl->hasAttr<NSConsumedAttr>()) {
+ Diag(newDecl->getLocation(), diag::warn_nsconsumed_attribute_mismatch);
+ Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter";
}
- if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() !=
- Overridden->hasAttr<NSReturnsNotRetainedAttr>())) {
- Diag(NewMethod->getLocation(),
- diag::err_nsreturns_retained_attribute_mismatch) << 0;
- Diag(Overridden->getLocation(), diag::note_previous_decl)
- << "method";
- }
- ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(),
- oe = Overridden->param_end();
- for (ObjCMethodDecl::param_iterator
- ni = NewMethod->param_begin(), ne = NewMethod->param_end();
- ni != ne && oi != oe; ++ni, ++oi) {
- const ParmVarDecl *oldDecl = (*oi);
- ParmVarDecl *newDecl = (*ni);
- if (newDecl->hasAttr<NSConsumedAttr>() !=
- oldDecl->hasAttr<NSConsumedAttr>()) {
- Diag(newDecl->getLocation(),
- diag::err_nsconsumed_attribute_mismatch);
- Diag(oldDecl->getLocation(), diag::note_previous_decl)
- << "parameter";
- }
+
+ // A parameter of the overriding method should be annotated with noescape
+ // if the corresponding parameter of the overridden method is annotated.
+ if (oldDecl->hasAttr<NoEscapeAttr>() && !newDecl->hasAttr<NoEscapeAttr>()) {
+ Diag(newDecl->getLocation(),
+ diag::warn_overriding_method_missing_noescape);
+ Diag(oldDecl->getLocation(), diag::note_overridden_marked_noescape);
}
}
}
@@ -933,8 +943,9 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
assert(ClassName && "Missing class identifier");
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc,
- LookupOrdinaryName, ForRedeclaration);
+ NamedDecl *PrevDecl =
+ LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
+ forRedeclarationInCurContext());
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
@@ -1085,16 +1096,18 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLocation) {
// Look for previous declaration of alias name
- NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation,
- LookupOrdinaryName, ForRedeclaration);
+ NamedDecl *ADecl =
+ LookupSingleName(TUScope, AliasName, AliasLocation, LookupOrdinaryName,
+ forRedeclarationInCurContext());
if (ADecl) {
Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName;
Diag(ADecl->getLocation(), diag::note_previous_declaration);
return nullptr;
}
// Check for class declaration
- NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
- LookupOrdinaryName, ForRedeclaration);
+ NamedDecl *CDeclU =
+ LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName,
+ forRedeclarationInCurContext());
if (const TypedefNameDecl *TDecl =
dyn_cast_or_null<TypedefNameDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
@@ -1102,7 +1115,8 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
ClassName = IDecl->getIdentifier();
CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName,
+ forRedeclarationInCurContext());
}
}
}
@@ -1164,7 +1178,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc,
- ForRedeclaration);
+ forRedeclarationInCurContext());
ObjCProtocolDecl *PDecl = nullptr;
if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) {
// If we already have a definition, complain.
@@ -1720,7 +1734,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
for (const IdentifierLocPair &IdentPair : IdentList) {
IdentifierInfo *Ident = IdentPair.first;
ObjCProtocolDecl *PrevDecl = LookupProtocol(Ident, IdentPair.second,
- ForRedeclaration);
+ forRedeclarationInCurContext());
ObjCProtocolDecl *PDecl
= ObjCProtocolDecl::Create(Context, CurContext, Ident,
IdentPair.second, AtProtocolLoc,
@@ -1911,7 +1925,7 @@ Decl *Sema::ActOnStartClassImplementation(
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
= LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
@@ -2987,7 +3001,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
= LookupSingleName(TUScope, IdentList[i], IdentLocs[i],
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName, forRedeclarationInCurContext());
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
// GCC apparently allows the following idiom:
//
@@ -3707,6 +3721,26 @@ static void DiagnoseWeakIvars(Sema &S, ObjCImplementationDecl *ID) {
}
}
+/// Diagnose attempts to use flexible array member with retainable object type.
+static void DiagnoseRetainableFlexibleArrayMember(Sema &S,
+ ObjCInterfaceDecl *ID) {
+ if (!S.getLangOpts().ObjCAutoRefCount)
+ return;
+
+ for (auto ivar = ID->all_declared_ivar_begin(); ivar;
+ ivar = ivar->getNextIvar()) {
+ if (ivar->isInvalidDecl())
+ continue;
+ QualType IvarTy = ivar->getType();
+ if (IvarTy->isIncompleteArrayType() &&
+ (IvarTy.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) &&
+ IvarTy->isObjCLifetimeType()) {
+ S.Diag(ivar->getLocation(), diag::err_flexible_array_arc_retainable);
+ ivar->setInvalidDecl();
+ }
+ }
+}
+
Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
switch (CurContext->getDeclKind()) {
case Decl::ObjCInterface:
@@ -3727,6 +3761,96 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
}
}
+static bool IsVariableSizedType(QualType T) {
+ if (T->isIncompleteArrayType())
+ return true;
+ const auto *RecordTy = T->getAs<RecordType>();
+ return (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember());
+}
+
+static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
+ ObjCInterfaceDecl *IntfDecl = nullptr;
+ ObjCInterfaceDecl::ivar_range Ivars = llvm::make_range(
+ ObjCInterfaceDecl::ivar_iterator(), ObjCInterfaceDecl::ivar_iterator());
+ if ((IntfDecl = dyn_cast<ObjCInterfaceDecl>(OCD))) {
+ Ivars = IntfDecl->ivars();
+ } else if (auto *ImplDecl = dyn_cast<ObjCImplementationDecl>(OCD)) {
+ IntfDecl = ImplDecl->getClassInterface();
+ Ivars = ImplDecl->ivars();
+ } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(OCD)) {
+ if (CategoryDecl->IsClassExtension()) {
+ IntfDecl = CategoryDecl->getClassInterface();
+ Ivars = CategoryDecl->ivars();
+ }
+ }
+
+ // Check if variable sized ivar is in interface and visible to subclasses.
+ if (!isa<ObjCInterfaceDecl>(OCD)) {
+ for (auto ivar : Ivars) {
+ if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) {
+ S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility)
+ << ivar->getDeclName() << ivar->getType();
+ }
+ }
+ }
+
+ // Subsequent checks require interface decl.
+ if (!IntfDecl)
+ return;
+
+ // Check if variable sized ivar is followed by another ivar.
+ for (ObjCIvarDecl *ivar = IntfDecl->all_declared_ivar_begin(); ivar;
+ ivar = ivar->getNextIvar()) {
+ if (ivar->isInvalidDecl() || !ivar->getNextIvar())
+ continue;
+ QualType IvarTy = ivar->getType();
+ bool IsInvalidIvar = false;
+ if (IvarTy->isIncompleteArrayType()) {
+ S.Diag(ivar->getLocation(), diag::err_flexible_array_not_at_end)
+ << ivar->getDeclName() << IvarTy
+ << TTK_Class; // Use "class" for Obj-C.
+ IsInvalidIvar = true;
+ } else if (const RecordType *RecordTy = IvarTy->getAs<RecordType>()) {
+ if (RecordTy->getDecl()->hasFlexibleArrayMember()) {
+ S.Diag(ivar->getLocation(),
+ diag::err_objc_variable_sized_type_not_at_end)
+ << ivar->getDeclName() << IvarTy;
+ IsInvalidIvar = true;
+ }
+ }
+ if (IsInvalidIvar) {
+ S.Diag(ivar->getNextIvar()->getLocation(),
+ diag::note_next_ivar_declaration)
+ << ivar->getNextIvar()->getSynthesize();
+ ivar->setInvalidDecl();
+ }
+ }
+
+ // Check if ObjC container adds ivars after variable sized ivar in superclass.
+ // Perform the check only if OCD is the first container to declare ivars to
+ // avoid multiple warnings for the same ivar.
+ ObjCIvarDecl *FirstIvar =
+ (Ivars.begin() == Ivars.end()) ? nullptr : *Ivars.begin();
+ if (FirstIvar && (FirstIvar == IntfDecl->all_declared_ivar_begin())) {
+ const ObjCInterfaceDecl *SuperClass = IntfDecl->getSuperClass();
+ while (SuperClass && SuperClass->ivar_empty())
+ SuperClass = SuperClass->getSuperClass();
+ if (SuperClass) {
+ auto IvarIter = SuperClass->ivar_begin();
+ std::advance(IvarIter, SuperClass->ivar_size() - 1);
+ const ObjCIvarDecl *LastIvar = *IvarIter;
+ if (IsVariableSizedType(LastIvar->getType())) {
+ S.Diag(FirstIvar->getLocation(),
+ diag::warn_superclass_variable_sized_type_not_at_end)
+ << FirstIvar->getDeclName() << LastIvar->getDeclName()
+ << LastIvar->getType() << SuperClass->getDeclName();
+ S.Diag(LastIvar->getLocation(), diag::note_entity_declared_at)
+ << LastIvar->getDeclName();
+ }
+ }
+ }
+}
+
// Note: For class/category implementations, allMethods is always null.
Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ArrayRef<DeclGroupPtrTy> allTUVars) {
@@ -3858,6 +3982,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
if (IDecl->hasDesignatedInitializers())
DiagnoseMissingDesignatedInitOverrides(IC, IDecl);
DiagnoseWeakIvars(*this, IC);
+ DiagnoseRetainableFlexibleArrayMember(*this, IDecl);
bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>();
if (IDecl->getSuperClass() == nullptr) {
@@ -3927,6 +4052,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
}
}
}
+ DiagnoseVariableSizedIvars(*this, OCD);
if (isInterfaceDeclKind) {
// Reject invalid vardecls.
for (unsigned i = 0, e = allTUVars.size(); i != e; i++) {
@@ -4209,6 +4335,10 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
// Then merge the declarations.
mergeObjCMethodDecls(ObjCMethod, overridden);
+ }
+
+ for (ObjCMethodDecl *overridden : overrides) {
+ CheckObjCMethodOverride(ObjCMethod, overridden);
if (ObjCMethod->isImplicit() && overridden->isImplicit())
continue; // Conflicting properties are detected elsewhere.
@@ -4433,7 +4563,7 @@ Decl *Sema::ActOnMethodDeclaration(
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName, forRedeclarationInCurContext());
LookupName(R, S);
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
@@ -4670,7 +4800,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
- if (T.getAddressSpace() != 0) {
+ if (T.getAddressSpace() != LangAS::Default) {
Diag(IdLoc, diag::err_arg_with_address_space);
Invalid = true;
}
@@ -4716,7 +4846,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
}
if (DS.isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
- << getLangOpts().CPlusPlus1z;
+ << getLangOpts().CPlusPlus17;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index deb6cbb53aff..67d1b02d1fca 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -145,7 +145,7 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
bool Sema::CheckDistantExceptionSpec(QualType T) {
// C++17 removes this rule in favor of putting exception specifications into
// the type system.
- if (getLangOpts().CPlusPlus1z)
+ if (getLangOpts().CPlusPlus17)
return false;
if (const PointerType *PT = T->getAs<PointerType>())
@@ -237,10 +237,10 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
}
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
- // Just completely ignore this under -fno-exceptions prior to C++1z.
- // In C++1z onwards, the exception specification is part of the type and
+ // Just completely ignore this under -fno-exceptions prior to C++17.
+ // In C++17 onwards, the exception specification is part of the type and
// we will diagnose mismatches anyway, so it's better to check for them here.
- if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus1z)
+ if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17)
return false;
OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
@@ -872,7 +872,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
// This is not an error in C++17 onwards, unless the noexceptness doesn't
// match, but in that case we have a full-on type mismatch, not just a
// type sugar mismatch.
- if (getLangOpts().CPlusPlus1z) {
+ if (getLangOpts().CPlusPlus17) {
DiagID = diag::warn_incompatible_exception_specs;
NestedDiagID = diag::warn_deep_exception_specs_differ;
}
@@ -892,7 +892,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(),
ToFunc, From->getSourceRange().getBegin(),
FromFunc, SourceLocation()) &&
- !getLangOpts().CPlusPlus1z;
+ !getLangOpts().CPlusPlus17;
}
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
@@ -953,7 +953,7 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
QualType T;
// In C++1z, just look at the function type of the callee.
- if (S.getLangOpts().CPlusPlus1z && isa<CallExpr>(E)) {
+ if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) {
E = cast<CallExpr>(E)->getCallee();
T = E->getType();
if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d3d7d8b67c70..929806ac6bfa 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -79,7 +79,8 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
if (const auto *A = D->getAttr<UnusedAttr>()) {
// [[maybe_unused]] should not diagnose uses, but __attribute__((unused))
// should diagnose them.
- if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) {
+ if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused &&
+ A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) {
const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
if (DC && !DC->hasAttr<UnusedAttr>())
S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
@@ -425,14 +426,6 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
if (Ty->isFunctionType()) {
- // If we are here, we are not calling a function but taking
- // its address (which is not allowed in OpenCL v1.0 s6.8.a.3).
- if (getLangOpts().OpenCL) {
- if (Diagnose)
- Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
- return ExprError();
- }
-
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc()))
@@ -722,8 +715,10 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
return ExprError();
E = Res.get();
- // If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to
- // double.
+ // 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 = Ty->getAs<BuiltinType>();
if (BTy && (BTy->getKind() == BuiltinType::Half ||
BTy->getKind() == BuiltinType::Float)) {
@@ -995,7 +990,7 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
return ResultType;
}
-/// \brief Hande arithmetic conversion from integer to float. Helper function
+/// \brief Handle arithmetic conversion from integer to float. Helper function
/// of UsualArithmeticConversions()
static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
ExprResult &IntExpr,
@@ -1502,8 +1497,9 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
- /*AllowRaw*/false, /*AllowTemplate*/false,
- /*AllowStringTemplate*/false) == Sema::LOLR_Error)
+ /*AllowRaw*/ false, /*AllowTemplate*/ false,
+ /*AllowStringTemplate*/ false,
+ /*DiagnoseMissing*/ true) == Sema::LOLR_Error)
return ExprError();
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
@@ -1594,8 +1590,9 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
switch (LookupLiteralOperator(UDLScope, R, ArgTy,
- /*AllowRaw*/false, /*AllowTemplate*/false,
- /*AllowStringTemplate*/true)) {
+ /*AllowRaw*/ false, /*AllowTemplate*/ false,
+ /*AllowStringTemplate*/ true,
+ /*DiagnoseMissing*/ true)) {
case LOLR_Cooked: {
llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars());
@@ -1628,6 +1625,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
}
case LOLR_Raw:
case LOLR_Template:
+ case LOLR_ErrorNoDiagnostic:
llvm_unreachable("unexpected literal operator lookup result");
case LOLR_Error:
return ExprError();
@@ -2806,6 +2804,8 @@ ExprResult Sema::BuildDeclarationNameExpr(
{
QualType type = VD->getType();
+ if (type.isNull())
+ return ExprError();
if (auto *FPT = type->getAs<FunctionProtoType>()) {
// C++ [except.spec]p17:
// An exception-specification is considered to be needed when:
@@ -3250,11 +3250,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// literal or a cooked one.
LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName);
switch (LookupLiteralOperator(UDLScope, R, CookedTy,
- /*AllowRaw*/true, /*AllowTemplate*/true,
- /*AllowStringTemplate*/false)) {
+ /*AllowRaw*/ true, /*AllowTemplate*/ true,
+ /*AllowStringTemplate*/ false,
+ /*DiagnoseMissing*/ !Literal.isImaginary)) {
+ case LOLR_ErrorNoDiagnostic:
+ // Lookup failure for imaginary constants isn't fatal, there's still the
+ // GNU extension producing _Complex types.
+ break;
case LOLR_Error:
return ExprError();
-
case LOLR_Cooked: {
Expr *Lit;
if (Literal.isFloatingLiteral()) {
@@ -3322,6 +3326,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Ty = Context.FloatTy;
else if (Literal.isLong)
Ty = Context.LongDoubleTy;
+ else if (Literal.isFloat16)
+ Ty = Context.Float16Ty;
else if (Literal.isFloat128)
Ty = Context.Float128Ty;
else
@@ -3470,10 +3476,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
// If this is an imaginary literal, create the ImaginaryLiteral wrapper.
- if (Literal.isImaginary)
+ if (Literal.isImaginary) {
Res = new (Context) ImaginaryLiteral(Res,
Context.getComplexType(Res->getType()));
+ Diag(Tok.getLocation(), diag::ext_imaginary_constant);
+ }
return Res;
}
@@ -4477,6 +4485,22 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
// Instantiate the expression.
+ //
+ // FIXME: Pass in a correct Pattern argument, otherwise
+ // getTemplateInstantiationArgs uses the lexical context of FD, e.g.
+ //
+ // template<typename T>
+ // struct A {
+ // static int FooImpl();
+ //
+ // template<typename Tp>
+ // // bug: default argument A<T>::FooImpl() is evaluated with 2-level
+ // // template argument list [[T], [Tp]], should be [[Tp]].
+ // friend A<Tp> Foo(int a);
+ // };
+ //
+ // template<typename T>
+ // A<T> Foo(int a = A<T>::FooImpl());
MultiLevelTemplateArgumentList MutiLevelArgList
= getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
@@ -5041,7 +5065,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
}
NeedsNewDecl = true;
- unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace();
+ LangAS AS = ArgType->getPointeeType().getAddressSpace();
QualType PointeeType = ParamType->getPointeeType();
PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
@@ -5104,6 +5128,87 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
}
}
+static bool enclosingClassIsRelatedToClassInWhichMembersWereFound(
+ const UnresolvedMemberExpr *const UME, Sema &S) {
+
+ const auto GetFunctionLevelDCIfCXXClass =
+ [](Sema &S) -> const CXXRecordDecl * {
+ const DeclContext *const DC = S.getFunctionLevelDeclContext();
+ if (!DC || !DC->getParent())
+ return nullptr;
+
+ // If the call to some member function was made from within a member
+ // function body 'M' return return 'M's parent.
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(DC))
+ return MD->getParent()->getCanonicalDecl();
+ // else the call was made from within a default member initializer of a
+ // class, so return the class.
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ return RD->getCanonicalDecl();
+ return nullptr;
+ };
+ // If our DeclContext is neither a member function nor a class (in the
+ // case of a lambda in a default member initializer), we can't have an
+ // enclosing 'this'.
+
+ const CXXRecordDecl *const CurParentClass = GetFunctionLevelDCIfCXXClass(S);
+ if (!CurParentClass)
+ return false;
+
+ // The naming class for implicit member functions call is the class in which
+ // name lookup starts.
+ const CXXRecordDecl *const NamingClass =
+ UME->getNamingClass()->getCanonicalDecl();
+ assert(NamingClass && "Must have naming class even for implicit access");
+
+ // If the unresolved member functions were found in a 'naming class' that is
+ // related (either the same or derived from) to the class that contains the
+ // member function that itself contained the implicit member access.
+
+ return CurParentClass == NamingClass ||
+ CurParentClass->isDerivedFrom(NamingClass);
+}
+
+static void
+tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
+ Sema &S, const UnresolvedMemberExpr *const UME, SourceLocation CallLoc) {
+
+ if (!UME)
+ return;
+
+ LambdaScopeInfo *const CurLSI = S.getCurLambda();
+ // Only try and implicitly capture 'this' within a C++ Lambda if it hasn't
+ // already been captured, or if this is an implicit member function call (if
+ // it isn't, an attempt to capture 'this' should already have been made).
+ if (!CurLSI || CurLSI->ImpCaptureStyle == CurLSI->ImpCap_None ||
+ !UME->isImplicitAccess() || CurLSI->isCXXThisCaptured())
+ return;
+
+ // Check if the naming class in which the unresolved members were found is
+ // related (same as or is a base of) to the enclosing class.
+
+ if (!enclosingClassIsRelatedToClassInWhichMembersWereFound(UME, S))
+ return;
+
+
+ DeclContext *EnclosingFunctionCtx = S.CurContext->getParent()->getParent();
+ // If the enclosing function is not dependent, then this lambda is
+ // capture ready, so if we can capture this, do so.
+ if (!EnclosingFunctionCtx->isDependentContext()) {
+ // If the current lambda and all enclosing lambdas can capture 'this' -
+ // then go ahead and capture 'this' (since our unresolved overload set
+ // contains at least one non-static member function).
+ if (!S.CheckCXXThisCapture(CallLoc, /*Explcit*/ false, /*Diagnose*/ false))
+ S.CheckCXXThisCapture(CallLoc);
+ } else if (S.CurContext->isDependentContext()) {
+ // ... since this is an implicit member reference, that might potentially
+ // involve a 'this' capture, mark 'this' for potential capture in
+ // enclosing lambdas.
+ if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None)
+ CurLSI->addPotentialThisCapture(CallLoc);
+ }
+}
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -5152,6 +5257,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs,
Context.DependentTy, VK_RValue, RParenLoc);
} else {
+
+ tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
+ *this, dyn_cast<UnresolvedMemberExpr>(Fn->IgnoreParens()),
+ Fn->getLocStart());
+
return new (Context) CallExpr(
Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc);
}
@@ -5651,8 +5761,8 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_ObjCObjectPointer:
switch (DestTy->getScalarTypeKind()) {
case Type::STK_CPointer: {
- unsigned SrcAS = SrcTy->getPointeeType().getAddressSpace();
- unsigned DestAS = DestTy->getPointeeType().getAddressSpace();
+ LangAS SrcAS = SrcTy->getPointeeType().getAddressSpace();
+ LangAS DestAS = DestTy->getPointeeType().getAddressSpace();
if (SrcAS != DestAS)
return CK_AddressSpaceConversion;
return CK_BitCast;
@@ -5924,9 +6034,9 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
// In OpenCL, casts between vectors of different types are not allowed.
// (See OpenCL 6.2).
if (SrcTy->isVectorType()) {
- if (!areLaxCompatibleVectorTypes(SrcTy, DestTy)
- || (getLangOpts().OpenCL &&
- (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) {
+ if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) ||
+ (getLangOpts().OpenCL &&
+ !Context.hasSameUnqualifiedType(DestTy, SrcTy))) {
Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
<< DestTy << SrcTy << R;
return ExprError();
@@ -6256,9 +6366,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
Qualifiers lhQual = lhptee.getQualifiers();
Qualifiers rhQual = rhptee.getQualifiers();
- unsigned ResultAddrSpace = 0;
- unsigned LAddrSpace = lhQual.getAddressSpace();
- unsigned RAddrSpace = rhQual.getAddressSpace();
+ LangAS ResultAddrSpace = LangAS::Default;
+ LangAS LAddrSpace = lhQual.getAddressSpace();
+ LangAS RAddrSpace = rhQual.getAddressSpace();
if (S.getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
// spaces is disallowed.
@@ -7132,6 +7242,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
commonExpr = commonRes.get();
}
+ // If the common expression is a class or array prvalue, materialize it
+ // so that we can safely refer to it multiple times.
+ if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() ||
+ commonExpr->getType()->isArrayType())) {
+ ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr);
+ if (MatExpr.isInvalid())
+ return ExprError();
+ commonExpr = MatExpr.get();
+ }
+
opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
commonExpr->getType(),
commonExpr->getValueKind(),
@@ -7391,11 +7511,19 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
// usually happen on valid code.
OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue);
ExprResult RHSPtr = &RHSExpr;
- CastKind K = CK_Invalid;
+ CastKind K;
return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false);
}
+/// This helper function returns true if QT is a vector type that has element
+/// type ElementType.
+static bool isVector(QualType QT, QualType ElementType) {
+ if (const VectorType *VT = QT->getAs<VectorType>())
+ return VT->getElementType() == ElementType;
+ return false;
+}
+
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
/// has code to accommodate several GCC extensions when type checking
/// pointers. Here are some objectionable examples that GCC considers warnings:
@@ -7514,6 +7642,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (unsupportedTypeConversion(*this, LHSType, RHSType))
return Incompatible;
+ // Disallow assigning a _Complex to a real type in C++ mode since it simply
+ // discards the imaginary part.
+ if (getLangOpts().CPlusPlus && RHSType->getAs<ComplexType>() &&
+ !LHSType->getAs<ComplexType>())
+ return Incompatible;
+
// Arithmetic conversions.
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
@@ -7526,8 +7660,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) {
// U* -> T*
if (isa<PointerType>(RHSType)) {
- unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
- unsigned AddrSpaceR = RHSType->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceR = RHSType->getPointeeType().getAddressSpace();
Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return checkPointerTypesForAssignment(*this, LHSType, RHSType);
}
@@ -7562,10 +7696,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// U^ -> void*
if (RHSType->getAs<BlockPointerType>()) {
if (LHSPointer->getPointeeType()->isVoidType()) {
- unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
- unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>()
- ->getPointeeType()
- .getAddressSpace();
+ LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
+ LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
Kind =
AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return Compatible;
@@ -7579,12 +7713,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (isa<BlockPointerType>(LHSType)) {
// U^ -> T^
if (RHSType->isBlockPointerType()) {
- unsigned AddrSpaceL = LHSType->getAs<BlockPointerType>()
- ->getPointeeType()
- .getAddressSpace();
- unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>()
- ->getPointeeType()
- .getAddressSpace();
+ LangAS AddrSpaceL = LHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
+ LangAS AddrSpaceR = RHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType);
}
@@ -7769,7 +7903,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
}
}
- CastKind Kind = CK_Invalid;
+ CastKind Kind;
if (CheckAssignmentConstraints(it->getType(), RHS, Kind)
== Compatible) {
RHS = ImpCastExprToType(RHS.get(), it->getType(), Kind);
@@ -7885,7 +8019,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
}
}
- CastKind Kind = CK_Invalid;
+ CastKind Kind;
Sema::AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
@@ -7980,7 +8114,7 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
unsigned &DiagID) {
// The conversion to apply to the scalar before splatting it,
// if necessary.
- CastKind scalarCast = CK_Invalid;
+ CastKind scalarCast = CK_NoOp;
if (vectorEltTy->isIntegralType(S.Context)) {
if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() ||
@@ -8011,13 +8145,32 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
// Adjust scalar if desired.
if (scalar) {
- if (scalarCast != CK_Invalid)
+ if (scalarCast != CK_NoOp)
*scalar = S.ImpCastExprToType(scalar->get(), vectorEltTy, scalarCast);
*scalar = S.ImpCastExprToType(scalar->get(), vectorTy, CK_VectorSplat);
}
return false;
}
+/// Convert vector E to a vector with the same number of elements but different
+/// element type.
+static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) {
+ const auto *VecTy = E->getType()->getAs<VectorType>();
+ assert(VecTy && "Expression E must be a vector");
+ QualType NewVecTy = S.Context.getVectorType(ElementType,
+ VecTy->getNumElements(),
+ VecTy->getVectorKind());
+
+ // Look through the implicit cast. Return the subexpression if its type is
+ // NewVecTy.
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ if (ICE->getSubExpr()->getType() == NewVecTy)
+ return ICE->getSubExpr();
+
+ auto Cast = ElementType->isIntegerType() ? CK_IntegralCast : CK_FloatingCast;
+ return S.ImpCastExprToType(E, NewVecTy, Cast);
+}
+
/// Test if a (constant) integer Int can be casted to another integer type
/// IntTy without losing precision.
static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int,
@@ -8459,6 +8612,21 @@ static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
<< 0 /* one pointer */ << Pointer->getSourceRange();
}
+/// \brief Diagnose invalid arithmetic on a null pointer.
+///
+/// If \p IsGNUIdiom is true, the operation is using the 'p = (i8*)nullptr + n'
+/// idiom, which we recognize as a GNU extension.
+///
+static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc,
+ Expr *Pointer, bool IsGNUIdiom) {
+ if (IsGNUIdiom)
+ S.Diag(Loc, diag::warn_gnu_null_ptr_arith)
+ << Pointer->getSourceRange();
+ else
+ S.Diag(Loc, diag::warn_pointer_arith_null_ptr)
+ << S.getLangOpts().CPlusPlus << Pointer->getSourceRange();
+}
+
/// \brief Diagnose invalid arithmetic on two function pointers.
static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
@@ -8753,6 +8921,21 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
if (!IExp->getType()->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
+ // Adding to a null pointer results in undefined behavior.
+ if (PExp->IgnoreParenCasts()->isNullPointerConstant(
+ Context, Expr::NPC_ValueDependentIsNotNull)) {
+ // In C++ adding zero to a null pointer is defined.
+ llvm::APSInt KnownVal;
+ if (!getLangOpts().CPlusPlus ||
+ (!IExp->isValueDependent() &&
+ (!IExp->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) {
+ // Check the conditions to see if this is the 'p = nullptr + n' idiom.
+ bool IsGNUIdiom = BinaryOperator::isNullPointerArithmeticExtension(
+ Context, BO_Add, PExp, IExp);
+ diagnoseArithmeticOnNullPointer(*this, Loc, PExp, IsGNUIdiom);
+ }
+ }
+
if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
return QualType();
@@ -8814,6 +8997,20 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
// The result type of a pointer-int computation is the pointer type.
if (RHS.get()->getType()->isIntegerType()) {
+ // Subtracting from a null pointer should produce a warning.
+ // The last argument to the diagnose call says this doesn't match the
+ // GNU int-to-pointer idiom.
+ if (LHS.get()->IgnoreParenCasts()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull)) {
+ // In C++ adding zero to a null pointer is defined.
+ llvm::APSInt KnownVal;
+ if (!getLangOpts().CPlusPlus ||
+ (!RHS.get()->isValueDependent() &&
+ (!RHS.get()->EvaluateAsInt(KnownVal, Context) || KnownVal != 0))) {
+ diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false);
+ }
+ }
+
if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get()))
return QualType();
@@ -8849,6 +9046,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
LHS.get(), RHS.get()))
return QualType();
+ // FIXME: Add warnings for nullptr - ptr.
+
// The pointee type may have zero size. As an extension, a structure or
// union may have zero size or an array may have zero length. In this
// case subtraction does not make sense.
@@ -9124,9 +9323,11 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
return;
// Ignore anonymous enums.
- if (!LHSEnumType->getDecl()->getIdentifier())
+ if (!LHSEnumType->getDecl()->getIdentifier() &&
+ !LHSEnumType->getDecl()->getTypedefNameForAnonDecl())
return;
- if (!RHSEnumType->getDecl()->getIdentifier())
+ if (!RHSEnumType->getDecl()->getIdentifier() &&
+ !RHSEnumType->getDecl()->getTypedefNameForAnonDecl())
return;
if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
@@ -9614,8 +9815,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
}
- unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace();
- unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace();
+ LangAS AddrSpaceL = LCanPointeeTy.getAddressSpace();
+ LangAS AddrSpaceR = RCanPointeeTy.getAddressSpace();
CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion
: CK_BitCast;
if (LHSIsNull && !RHSIsNull)
@@ -10145,22 +10346,23 @@ static bool IsTypeModifiable(QualType Ty, bool IsDereference) {
return !Ty.isConstQualified();
}
+// Update err_typecheck_assign_const and note_typecheck_assign_const
+// when this enum is changed.
+enum {
+ ConstFunction,
+ ConstVariable,
+ ConstMember,
+ ConstMethod,
+ NestedConstMember,
+ ConstUnknown, // Keep as last element
+};
+
/// Emit the "read-only variable not assignable" error and print notes to give
/// more information about why the variable is not assignable, such as pointing
/// to the declaration of a const variable, showing that a method is const, or
/// that the function is returning a const reference.
static void DiagnoseConstAssignment(Sema &S, const Expr *E,
SourceLocation Loc) {
- // Update err_typecheck_assign_const and note_typecheck_assign_const
- // when this enum is changed.
- enum {
- ConstFunction,
- ConstVariable,
- ConstMember,
- ConstMethod,
- ConstUnknown, // Keep as last element
- };
-
SourceRange ExprRange = E->getSourceRange();
// Only emit one error on the first const found. All other consts will emit
@@ -10270,6 +10472,66 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown;
}
+enum OriginalExprKind {
+ OEK_Variable,
+ OEK_Member,
+ OEK_LValue
+};
+
+static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD,
+ const RecordType *Ty,
+ SourceLocation Loc, SourceRange Range,
+ OriginalExprKind OEK,
+ bool &DiagnosticEmitted,
+ bool IsNested = false) {
+ // We walk the record hierarchy breadth-first to ensure that we print
+ // diagnostics in field nesting order.
+ // First, check every field for constness.
+ for (const FieldDecl *Field : Ty->getDecl()->fields()) {
+ if (Field->getType().isConstQualified()) {
+ if (!DiagnosticEmitted) {
+ S.Diag(Loc, diag::err_typecheck_assign_const)
+ << Range << NestedConstMember << OEK << VD
+ << IsNested << Field;
+ DiagnosticEmitted = true;
+ }
+ S.Diag(Field->getLocation(), diag::note_typecheck_assign_const)
+ << NestedConstMember << IsNested << Field
+ << Field->getType() << Field->getSourceRange();
+ }
+ }
+ // Then, recurse.
+ for (const FieldDecl *Field : Ty->getDecl()->fields()) {
+ QualType FTy = Field->getType();
+ if (const RecordType *FieldRecTy = FTy->getAs<RecordType>())
+ DiagnoseRecursiveConstFields(S, VD, FieldRecTy, Loc, Range,
+ OEK, DiagnosticEmitted, true);
+ }
+}
+
+/// Emit an error for the case where a record we are trying to assign to has a
+/// const-qualified field somewhere in its hierarchy.
+static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E,
+ SourceLocation Loc) {
+ QualType Ty = E->getType();
+ assert(Ty->isRecordType() && "lvalue was not record?");
+ SourceRange Range = E->getSourceRange();
+ const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>();
+ bool DiagEmitted = false;
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ DiagnoseRecursiveConstFields(S, ME->getMemberDecl(), RTy, Loc,
+ Range, OEK_Member, DiagEmitted);
+ else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ DiagnoseRecursiveConstFields(S, DRE->getDecl(), RTy, Loc,
+ Range, OEK_Variable, DiagEmitted);
+ else
+ DiagnoseRecursiveConstFields(S, nullptr, RTy, Loc,
+ Range, OEK_LValue, DiagEmitted);
+ if (!DiagEmitted)
+ DiagnoseConstAssignment(S, E, Loc);
+}
+
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
@@ -10345,6 +10607,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_ConstAddrSpace:
DiagnoseConstAssignment(S, E, Loc);
return true;
+ case Expr::MLV_ConstQualifiedField:
+ DiagnoseRecursiveConstFields(S, E, Loc);
+ return true;
case Expr::MLV_ArrayType:
case Expr::MLV_ArrayTemporary:
DiagID = diag::err_typecheck_array_not_modifiable_lvalue;
@@ -10654,7 +10919,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return QualType();
}
// Increment of bool sets it to true, but is deprecated.
- S.Diag(OpLoc, S.getLangOpts().CPlusPlus1z ? diag::ext_increment_bool
+ S.Diag(OpLoc, S.getLangOpts().CPlusPlus17 ? diag::ext_increment_bool
: diag::warn_increment_bool)
<< Op->getSourceRange();
} else if (S.getLangOpts().CPlusPlus && ResType->isEnumeralType()) {
@@ -10838,10 +11103,17 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
// Make sure to ignore parentheses in subsequent checks
Expr *op = OrigOp.get()->IgnoreParens();
- // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
- if (LangOpts.OpenCL && op->getType()->isFunctionType()) {
- Diag(op->getExprLoc(), diag::err_opencl_taking_function_address);
- return QualType();
+ // In OpenCL captures for blocks called as lambda functions
+ // are located in the private address space. Blocks used in
+ // enqueue_kernel can be located in a different address space
+ // depending on a vendor implementation. Thus preventing
+ // taking an address of the capture to avoid invalid AS casts.
+ if (LangOpts.OpenCL) {
+ auto* VarRef = dyn_cast<DeclRefExpr>(op);
+ if (VarRef && VarRef->refersToEnclosingVariableOrCapture()) {
+ Diag(op->getExprLoc(), diag::err_opencl_taking_address_capture);
+ return QualType();
+ }
}
if (getLangOpts().C99) {
@@ -11103,6 +11375,7 @@ BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) {
case tok::greater: Opc = BO_GT; break;
case tok::exclaimequal: Opc = BO_NE; break;
case tok::equalequal: Opc = BO_EQ; break;
+ case tok::spaceship: Opc = BO_Cmp; break;
case tok::amp: Opc = BO_And; break;
case tok::caret: Opc = BO_Xor; break;
case tok::pipe: Opc = BO_Or; break;
@@ -11233,6 +11506,70 @@ static NamedDecl *getDeclFromExpr(Expr *E) {
return nullptr;
}
+// This helper function promotes a binary operator's operands (which are of a
+// half vector type) to a vector of floats and then truncates the result to
+// a vector of either half or short.
+static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
+ BinaryOperatorKind Opc, QualType ResultTy,
+ ExprValueKind VK, ExprObjectKind OK,
+ bool IsCompAssign, SourceLocation OpLoc,
+ FPOptions FPFeatures) {
+ auto &Context = S.getASTContext();
+ assert((isVector(ResultTy, Context.HalfTy) ||
+ isVector(ResultTy, Context.ShortTy)) &&
+ "Result must be a vector of half or short");
+ assert(isVector(LHS.get()->getType(), Context.HalfTy) &&
+ isVector(RHS.get()->getType(), Context.HalfTy) &&
+ "both operands expected to be a half vector");
+
+ RHS = convertVector(RHS.get(), Context.FloatTy, S);
+ QualType BinOpResTy = RHS.get()->getType();
+
+ // If Opc is a comparison, ResultType is a vector of shorts. In that case,
+ // change BinOpResTy to a vector of ints.
+ if (isVector(ResultTy, Context.ShortTy))
+ BinOpResTy = S.GetSignedVectorType(BinOpResTy);
+
+ if (IsCompAssign)
+ return new (Context) CompoundAssignOperator(
+ LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy,
+ OpLoc, FPFeatures);
+
+ LHS = convertVector(LHS.get(), Context.FloatTy, S);
+ auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
+ VK, OK, OpLoc, FPFeatures);
+ return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S);
+}
+
+static std::pair<ExprResult, ExprResult>
+CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
+ Expr *RHSExpr) {
+ ExprResult LHS = LHSExpr, RHS = RHSExpr;
+ if (!S.getLangOpts().CPlusPlus) {
+ // C cannot handle TypoExpr nodes on either side of a binop because it
+ // doesn't handle dependent types properly, so make sure any TypoExprs have
+ // been dealt with before checking the operands.
+ LHS = S.CorrectDelayedTyposInExpr(LHS);
+ RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) {
+ if (Opc != BO_Assign)
+ return ExprResult(E);
+ // Avoid correcting the RHS to the same Expr as the LHS.
+ Decl *D = getDeclFromExpr(E);
+ return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
+ });
+ }
+ return std::make_pair(LHS, RHS);
+}
+
+/// Returns true if conversion between vectors of halfs and vectors of floats
+/// is needed.
+static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
+ QualType SrcType) {
+ return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType &&
+ !Ctx.getTargetInfo().useFP16ConversionIntrinsics() &&
+ isVector(SrcType, Ctx.HalfTy);
+}
+
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
/// operator @p Opc at location @c TokLoc. This routine only supports
/// built-in operations; ActOnBinOp handles overloaded operators.
@@ -11264,22 +11601,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
QualType CompResultTy; // Type of computation result
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
+ bool ConvertHalfVec = false;
- if (!getLangOpts().CPlusPlus) {
- // C cannot handle TypoExpr nodes on either side of a binop because it
- // doesn't handle dependent types properly, so make sure any TypoExprs have
- // been dealt with before checking the operands.
- LHS = CorrectDelayedTyposInExpr(LHSExpr);
- RHS = CorrectDelayedTyposInExpr(RHSExpr, [Opc, LHS](Expr *E) {
- if (Opc != BO_Assign)
- return ExprResult(E);
- // Avoid correcting the RHS to the same Expr as the LHS.
- Decl *D = getDeclFromExpr(E);
- return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
- });
- if (!LHS.isUsable() || !RHS.isUsable())
- return ExprError();
- }
+ std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprError();
if (getLangOpts().OpenCL) {
QualType LHSTy = LHSExpr->getType();
@@ -11327,6 +11653,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_Mul:
case BO_Div:
+ ConvertHalfVec = true;
ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false,
Opc == BO_Div);
break;
@@ -11334,9 +11661,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc);
break;
case BO_Add:
+ ConvertHalfVec = true;
ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_Sub:
+ ConvertHalfVec = true;
ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc);
break;
case BO_Shl:
@@ -11347,12 +11676,21 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_LT:
case BO_GE:
case BO_GT:
+ ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
break;
case BO_EQ:
case BO_NE:
+ ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false);
break;
+ case BO_Cmp:
+ // FIXME: Implement proper semantic checking of '<=>'.
+ ConvertHalfVec = true;
+ ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
+ if (!ResultTy.isNull())
+ ResultTy = Context.VoidTy;
+ break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
LLVM_FALLTHROUGH;
@@ -11362,10 +11700,12 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_LAnd:
case BO_LOr:
+ ConvertHalfVec = true;
ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_MulAssign:
case BO_DivAssign:
+ ConvertHalfVec = true;
CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true,
Opc == BO_DivAssign);
CompLHSTy = CompResultTy;
@@ -11379,11 +11719,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_AddAssign:
+ ConvertHalfVec = true;
CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_SubAssign:
+ ConvertHalfVec = true;
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
@@ -11416,6 +11758,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
+ // Some of the binary operations require promoting operands of half vector to
+ // float vectors and truncating the result back to half vector. For now, we do
+ // this only when HalfArgsAndReturn is set (that is, when the target is arm or
+ // arm64).
+ assert(isVector(RHS.get()->getType(), Context.HalfTy) ==
+ isVector(LHS.get()->getType(), Context.HalfTy) &&
+ "both sides are half vectors or neither sides are");
+ ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context,
+ LHS.get()->getType());
+
// Check for array bounds violations for both sides of the BinaryOperator
CheckArrayAccess(LHS.get());
CheckArrayAccess(RHS.get());
@@ -11438,14 +11790,26 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts()))
DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
- if (CompResultTy.isNull())
+ // Opc is not a compound assignment if CompResultTy is null.
+ if (CompResultTy.isNull()) {
+ if (ConvertHalfVec)
+ return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false,
+ OpLoc, FPFeatures);
return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
OK, OpLoc, FPFeatures);
+ }
+
+ // Handle compound assignments.
if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
OK = LHS.get()->getObjectKind();
}
+
+ if (ConvertHalfVec)
+ return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true,
+ OpLoc, FPFeatures);
+
return new (Context) CompoundAssignOperator(
LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy,
OpLoc, FPFeatures);
@@ -11693,6 +12057,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
+ ExprResult LHS, RHS;
+ std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprError();
+ LHSExpr = LHS.get();
+ RHSExpr = RHS.get();
+
// We want to end up calling one of checkPseudoObjectAssignment
// (if the LHS is a pseudo-object), BuildOverloadedBinOp (if
// both expressions are overloadable or either is type-dependent),
@@ -11796,6 +12167,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
QualType resultType;
+ bool ConvertHalfVec = false;
if (getLangOpts().OpenCL) {
QualType Ty = InputExpr->getType();
// The only legal unary operation for atomics is '&'.
@@ -11835,6 +12207,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Minus:
Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid()) return ExprError();
+ // Unary plus and minus require promoting an operand of half vector to a
+ // float vector and truncating the result back to a half vector. For now, we
+ // do this only when HalfArgsAndReturns is set (that is, when the target is
+ // arm or arm64).
+ ConvertHalfVec =
+ needsConversionOfHalfVec(true, Context, Input.get()->getType());
+
+ // If the operand is a half vector, promote it to a float vector.
+ if (ConvertHalfVec)
+ Input = convertVector(Input.get(), Context.FloatTy, *this);
resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
@@ -11972,8 +12354,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Opc != UO_AddrOf && Opc != UO_Deref)
CheckArrayAccess(Input.get());
- return new (Context)
+ auto *UO = new (Context)
UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc);
+ // Convert the result back to a half vector.
+ if (ConvertHalfVec)
+ return convertVector(UO, Context.HalfTy, *this);
+ return UO;
}
/// \brief Determine whether the given expression is a qualified member
@@ -12211,15 +12597,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
&& RequireCompleteType(BuiltinLoc, ArgTy,
diag::err_offsetof_incomplete_type, TypeRange))
return ExprError();
-
- // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
- // GCC extension, diagnose them.
- // FIXME: This diagnostic isn't actually visible because the location is in
- // a system header!
- if (Components.size() != 1)
- Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
- << SourceRange(Components[1].LocStart, Components.back().LocEnd);
-
+
bool DidWarnAboutNonPOD = false;
QualType CurrentType = ArgTy;
SmallVector<OffsetOfNode, 4> Comps;
@@ -12482,8 +12860,8 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
// Look for an explicit signature in that function type.
FunctionProtoTypeLoc ExplicitSignature;
- TypeLoc tmp = Sig->getTypeLoc().IgnoreParens();
- if ((ExplicitSignature = tmp.getAs<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
@@ -13366,7 +13744,7 @@ void Sema::PopExpressionEvaluationContext() {
// are part of function-signatures. Be mindful that P0315 (Lambdas in
// unevaluated contexts) might lift some of these restrictions in a
// future version.
- if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus1z)
+ if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus17)
for (const auto *L : Rec.Lambdas)
Diag(L->getLocStart(), D);
} else {
@@ -13591,29 +13969,21 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
- bool AlreadyInstantiated = false;
- SourceLocation PointOfInstantiation = Loc;
- if (FunctionTemplateSpecializationInfo *SpecInfo
- = Func->getTemplateSpecializationInfo()) {
- if (SpecInfo->getPointOfInstantiation().isInvalid())
- SpecInfo->setPointOfInstantiation(Loc);
- else if (SpecInfo->getTemplateSpecializationKind()
- == TSK_ImplicitInstantiation) {
- AlreadyInstantiated = true;
- PointOfInstantiation = SpecInfo->getPointOfInstantiation();
- }
- } else if (MemberSpecializationInfo *MSInfo
- = Func->getMemberSpecializationInfo()) {
- if (MSInfo->getPointOfInstantiation().isInvalid())
- MSInfo->setPointOfInstantiation(Loc);
- else if (MSInfo->getTemplateSpecializationKind()
- == TSK_ImplicitInstantiation) {
- AlreadyInstantiated = true;
- PointOfInstantiation = MSInfo->getPointOfInstantiation();
- }
- }
-
- if (!AlreadyInstantiated || Func->isConstexpr()) {
+ 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())
@@ -13650,6 +14020,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
!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);
@@ -13973,8 +14345,13 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
bool ByRef = true;
// Using an LValue reference type is consistent with Lambdas (see below).
if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) {
- if (S.IsOpenMPCapturedDecl(Var))
+ if (S.IsOpenMPCapturedDecl(Var)) {
+ bool HasConst = DeclRefType.isConstQualified();
DeclRefType = DeclRefType.getUnqualifiedType();
+ // Don't lose diagnostics about assignments to const.
+ if (HasConst)
+ DeclRefType.addConst();
+ }
ByRef = S.IsOpenMPCapturedByRef(Var, RSI->OpenMPLevel);
}
@@ -13997,6 +14374,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
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(Var, RefersToCapturedVariable,
DeclRefType, VK_LValue, Loc);
@@ -14167,6 +14546,7 @@ bool Sema::tryCaptureVariable(
bool IsGlobal = !Var->hasLocalStorage();
if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var)))
return true;
+ Var = Var->getCanonicalDecl();
// Walk up the stack to determine whether we can capture the variable,
// performing the "simple" checks that don't depend on type. We stop when
@@ -14248,14 +14628,16 @@ bool Sema::tryCaptureVariable(
// just break here. Similarly, global variables that are captured in a
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
- auto IsTargetCap = isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
+ bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel);
+ auto IsTargetCap = !IsOpenMPPrivateDecl &&
+ isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
// When we detect target captures we are looking from inside the
// target region, therefore we need to propagate the capture from the
// enclosing region. Therefore, the capture is not initially nested.
if (IsTargetCap)
- FunctionScopesIndex--;
+ adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel);
- if (IsTargetCap || isOpenMPPrivateDecl(Var, RSI->OpenMPLevel)) {
+ if (IsTargetCap || IsOpenMPPrivateDecl) {
Nested = !IsTargetCap;
DeclRefType = DeclRefType.getUnqualifiedType();
CaptureType = Context.getLValueReferenceType(DeclRefType);
@@ -14451,9 +14833,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
bool OdrUseContext = isOdrUseContext(SemaRef);
+ bool UsableInConstantExpr =
+ Var->isUsableInConstantExpressions(SemaRef.Context);
bool NeedDefinition =
- OdrUseContext || (isEvaluatableContext(SemaRef) &&
- Var->isUsableInConstantExpressions(SemaRef.Context));
+ OdrUseContext || (isEvaluatableContext(SemaRef) && UsableInConstantExpr);
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -14472,24 +14855,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// instantiations of variable templates, except for those that could be used
// in a constant expression.
if (NeedDefinition && isTemplateInstantiation(TSK)) {
- bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
-
- if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
- if (Var->getPointOfInstantiation().isInvalid()) {
- // This is a modification of an existing AST node. Notify listeners.
- if (ASTMutationListener *L = SemaRef.getASTMutationListener())
- L->StaticDataMemberInstantiated(Var);
- } else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
- // Don't bother trying to instantiate it again, unless we might need
- // its initializer before we get to the end of the TU.
- TryInstantiating = false;
- }
-
- if (Var->getPointOfInstantiation().isInvalid())
- Var->setTemplateSpecializationKind(TSK, Loc);
+ // Per C++17 [temp.explicit]p10, we may instantiate despite an explicit
+ // instantiation declaration if a variable is usable in a constant
+ // expression (among other cases).
+ bool TryInstantiating =
+ TSK == TSK_ImplicitInstantiation ||
+ (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
if (TryInstantiating) {
SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
+ bool FirstInstantiation = PointOfInstantiation.isInvalid();
+ if (FirstInstantiation) {
+ PointOfInstantiation = Loc;
+ Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ }
+
bool InstantiationDependent = false;
bool IsNonDependent =
VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(
@@ -14498,11 +14878,17 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// Do not instantiate specializations that are still type-dependent.
if (IsNonDependent) {
- if (Var->isUsableInConstantExpressions(SemaRef.Context)) {
- // Do not defer instantiations of variables which could be used in a
+ if (UsableInConstantExpr) {
+ // Do not defer instantiations of variables that could be used in a
// constant expression.
SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
- } else {
+ } else if (FirstInstantiation ||
+ isa<VarTemplateSpecializationDecl>(Var)) {
+ // FIXME: For a specialization of a variable template, we don't
+ // distinguish between "declaration and type implicitly instantiated"
+ // and "implicit instantiation of definition requested", so we have
+ // no direct way to avoid enqueueing the pending instantiation
+ // multiple times.
SemaRef.PendingInstantiations
.push_back(std::make_pair(Var, PointOfInstantiation));
}
@@ -14522,7 +14908,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
IsVariableAConstantExpression(Var, SemaRef.Context)) {
// A reference initialized by a constant expression can never be
// odr-used, so simply ignore it.
- if (!Var->getType()->isReferenceType())
+ if (!Var->getType()->isReferenceType() ||
+ (SemaRef.LangOpts.OpenMP && SemaRef.IsOpenMPCapturedDecl(Var)))
SemaRef.MaybeODRUseExprs.insert(E);
} else if (OdrUseContext) {
MarkVarDeclODRUsed(Var, Loc, SemaRef,
@@ -14595,7 +14982,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
ME->getBase(), SemaRef.getLangOpts().AppleKext);
if (DM)
SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
-}
+}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
@@ -14810,10 +15197,24 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
if (Statement && getCurFunctionOrMethodDecl()) {
FunctionScopes.back()->PossiblyUnreachableDiags.
push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement));
+ return true;
}
- else
- Diag(Loc, PD);
-
+
+ // The initializer of a constexpr variable or of the first declaration of a
+ // static data member is not syntactically a constant evaluated constant,
+ // but nonetheless is always required to be a constant expression, so we
+ // can skip diagnosing.
+ // FIXME: Using the mangling context here is a hack.
+ if (auto *VD = dyn_cast_or_null<VarDecl>(
+ ExprEvalContexts.back().ManglingContextDecl)) {
+ if (VD->isConstexpr() ||
+ (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline()))
+ break;
+ // FIXME: For any other kind of variable, we should build a CFG for its
+ // initializer and check whether the context in question is reachable.
+ }
+
+ Diag(Loc, PD);
return true;
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index a9cf3ec7990b..9c842ded1e10 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/AlignedAllocation.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -1377,9 +1378,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
/// \brief Determine whether the given function is a non-placement
/// deallocation function.
static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
- if (FD->isInvalidDecl())
- return false;
-
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
return Method->isUsualDeallocationFunction();
@@ -1409,14 +1407,20 @@ namespace {
UsualDeallocFnInfo() : Found(), FD(nullptr) {}
UsualDeallocFnInfo(Sema &S, DeclAccessPair Found)
: Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())),
- HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) {
+ Destroying(false), HasSizeT(false), HasAlignValT(false),
+ CUDAPref(Sema::CFP_Native) {
// A function template declaration is never a usual deallocation function.
if (!FD)
return;
- if (FD->getNumParams() == 3)
+ unsigned NumBaseParams = 1;
+ if (FD->isDestroyingOperatorDelete()) {
+ Destroying = true;
+ ++NumBaseParams;
+ }
+ if (FD->getNumParams() == NumBaseParams + 2)
HasAlignValT = HasSizeT = true;
- else if (FD->getNumParams() == 2) {
- HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType();
+ else if (FD->getNumParams() == NumBaseParams + 1) {
+ HasSizeT = FD->getParamDecl(NumBaseParams)->getType()->isIntegerType();
HasAlignValT = !HasSizeT;
}
@@ -1430,6 +1434,12 @@ namespace {
bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize,
bool WantAlign) const {
+ // C++ P0722:
+ // A destroying operator delete is preferred over a non-destroying
+ // operator delete.
+ if (Destroying != Other.Destroying)
+ return Destroying;
+
// C++17 [expr.delete]p10:
// If the type has new-extended alignment, a function with a parameter
// of type std::align_val_t is preferred; otherwise a function without
@@ -1446,7 +1456,7 @@ namespace {
DeclAccessPair Found;
FunctionDecl *FD;
- bool HasSizeT, HasAlignValT;
+ bool Destroying, HasSizeT, HasAlignValT;
Sema::CUDAFunctionPreference CUDAPref;
};
}
@@ -1660,9 +1670,13 @@ static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
bool IsAligned = false;
if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) {
+ const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple();
+ StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling(
+ S.getASTContext().getTargetInfo().getPlatformName());
+
S.Diag(Loc, diag::warn_aligned_allocation_unavailable)
- << IsDelete << FD.getType().getAsString()
- << S.getASTContext().getTargetInfo().getTriple().str();
+ << IsDelete << FD.getType().getAsString() << OSName
+ << alignedAllocMinVersion(T.getOS()).getAsString();
S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable);
}
}
@@ -1734,20 +1748,27 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (AllocType.isNull())
return ExprError();
} else if (Deduced) {
+ bool Braced = (initStyle == CXXNewExpr::ListInit);
+ if (NumInits == 1) {
+ if (auto p = dyn_cast_or_null<InitListExpr>(Inits[0])) {
+ Inits = p->getInits();
+ NumInits = p->getNumInits();
+ Braced = true;
+ }
+ }
+
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
- if (initStyle == CXXNewExpr::ListInit ||
- (NumInits == 1 && isa<InitListExpr>(Inits[0])))
- return ExprError(Diag(Inits[0]->getLocStart(),
- diag::err_auto_new_list_init)
- << AllocType << TypeRange);
if (NumInits > 1) {
Expr *FirstBad = Inits[1];
return ExprError(Diag(FirstBad->getLocStart(),
diag::err_auto_new_ctor_multiple_expressions)
<< AllocType << TypeRange);
}
+ if (Braced && !getLangOpts().CPlusPlus17)
+ Diag(Initializer->getLocStart(), diag::ext_auto_new_list_init)
+ << AllocType << TypeRange;
Expr *Deduce = Inits[0];
QualType DeducedType;
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
@@ -2099,7 +2120,7 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (AllocType->isVariablyModifiedType())
return Diag(Loc, diag::err_variably_modified_new_type)
<< AllocType;
- else if (AllocType.getAddressSpace())
+ else if (AllocType.getAddressSpace() != LangAS::Default)
return Diag(Loc, diag::err_address_space_qualified_new)
<< AllocType.getUnqualifiedType()
<< AllocType.getQualifiers().getAddressSpaceAttributePrintValue();
@@ -3171,7 +3192,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee);
- if (Pointee.getAddressSpace())
+ if (Pointee.getAddressSpace() != LangAS::Default)
return Diag(Ex.get()->getLocStart(),
diag::err_address_space_qualified_delete)
<< Pointee.getUnqualifiedType()
@@ -3259,16 +3280,39 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
MarkFunctionReferenced(StartLoc, OperatorDelete);
- // Check access and ambiguity of operator delete and destructor.
+ // Check access and ambiguity of destructor if we're going to call it.
+ // Note that this is required even for a virtual delete.
+ bool IsVirtualDelete = false;
if (PointeeRD) {
if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
- CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor,
- PDiag(diag::err_access_dtor) << PointeeElem);
+ CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor,
+ PDiag(diag::err_access_dtor) << PointeeElem);
+ IsVirtualDelete = Dtor->isVirtual();
}
}
diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true,
*this);
+
+ // Convert the operand to the type of the first parameter of operator
+ // delete. This is only necessary if we selected a destroying operator
+ // delete that we are going to call (non-virtually); converting to void*
+ // is trivial and left to AST consumers to handle.
+ QualType ParamType = OperatorDelete->getParamDecl(0)->getType();
+ if (!IsVirtualDelete && !ParamType->getPointeeType()->isVoidType()) {
+ Qualifiers Qs = Pointee.getQualifiers();
+ if (Qs.hasCVRQualifiers()) {
+ // Qualifiers are irrelevant to this conversion; we're only looking
+ // for access and ambiguity.
+ Qs.removeCVRQualifiers();
+ QualType Unqual = Context.getPointerType(
+ Context.getQualifiedType(Pointee.getUnqualifiedType(), Qs));
+ Ex = ImpCastExprToType(Ex.get(), Unqual, CK_NoOp);
+ }
+ Ex = PerformImplicitConversion(Ex.get(), ParamType, AA_Passing);
+ if (Ex.isInvalid())
+ return ExprError();
+ }
}
CXXDeleteExpr *Result = new (Context) CXXDeleteExpr(
@@ -3282,7 +3326,7 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
bool IsDelete, bool CallCanBeVirtual,
bool WarnOnNonAbstractTypes,
SourceLocation DtorLoc) {
- if (!dtor || dtor->isVirtual() || !CallCanBeVirtual)
+ if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext())
return;
// C++ [expr.delete]p3:
@@ -3297,6 +3341,12 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>())
return;
+ // If the superclass is in a system header, there's nothing that can be done.
+ // The `delete` (where we emit the warning) can be in a system header,
+ // what matters for this warning is where the deleted type is defined.
+ if (getSourceManager().isInSystemHeader(PointeeRD->getLocation()))
+ return;
+
QualType ClassType = dtor->getThisType(Context)->getPointeeType();
if (PointeeRD->isAbstract()) {
// If the class is abstract, we warn by default, because we're
@@ -3797,7 +3847,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
<< From->getSourceRange();
}
- CastKind Kind = CK_Invalid;
+ CastKind Kind;
CXXCastPath BasePath;
if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
@@ -3817,7 +3867,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
case ICK_Pointer_Member: {
- CastKind Kind = CK_Invalid;
+ CastKind Kind;
CXXCastPath BasePath;
if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
@@ -4141,6 +4191,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsDestructible:
case UTT_IsNothrowDestructible:
case UTT_IsTriviallyDestructible:
+ case UTT_HasUniqueObjectRepresentations:
if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
return true;
@@ -4580,6 +4631,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
// Returns True if and only if T is a complete type at the point of the
// function call.
return !T->isIncompleteType();
+ case UTT_HasUniqueObjectRepresentations:
+ return C.hasUniqueObjectRepresentations(T);
}
}
@@ -4790,9 +4843,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
}
case BTT_IsSame:
return Self.Context.hasSameType(LhsT, RhsT);
- case BTT_TypeCompatible:
- return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(),
- RhsT.getUnqualifiedType());
+ case BTT_TypeCompatible: {
+ // GCC ignores cv-qualifiers on arrays for this builtin.
+ Qualifiers LhsQuals, RhsQuals;
+ QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals);
+ QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals);
+ return Self.Context.typesAreCompatible(Lhs, Rhs);
+ }
case BTT_IsConvertible:
case BTT_IsConvertibleTo: {
// C++0x [meta.rel]p4:
@@ -5173,9 +5230,16 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
break;
case RQ_LValue:
- if (!isIndirect && !LHS.get()->Classify(Context).isLValue())
- Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
- << RHSType << 1 << LHS.get()->getSourceRange();
+ if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) {
+ // C++2a allows functions with ref-qualifier & if they are also 'const'.
+ if (Proto->isConst())
+ Diag(Loc, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
+ : diag::ext_pointer_to_const_ref_member_on_rvalue);
+ else
+ Diag(Loc, diag::err_pointer_to_member_oper_value_classify)
+ << RHSType << 1 << LHS.get()->getSourceRange();
+ }
break;
case RQ_RValue:
@@ -5702,7 +5766,7 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
// happen in C++17, because it would mean we were computing the composite
// pointer type of dependent types, which should never happen.
if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) {
- assert(!S.getLangOpts().CPlusPlus1z &&
+ assert(!S.getLangOpts().CPlusPlus17 &&
"computing composite pointer type of dependent types");
return FunctionProtoType::ExceptionSpecInfo();
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index c3d0e2db76b6..03ddcc0a3eca 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -384,7 +384,9 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
}
}
- if (!HalvingSwizzle) {
+ // OpenCL mode requires swizzle length to be in accordance with accepted
+ // sizes. Clang however supports arbitrary lengths for other languages.
+ if (S.getLangOpts().OpenCL && !HalvingSwizzle) {
unsigned SwizzleLength = CompName->getLength();
if (HexSwizzle)
@@ -693,8 +695,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
Sema::RedeclarationKind Redecl;
};
QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(),
- R.isForRedeclaration() ? Sema::ForRedeclaration
- : Sema::NotForRedeclaration};
+ R.redeclarationKind()};
TE = SemaRef.CorrectTypoDelayed(
R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS,
llvm::make_unique<RecordMemberExprValidatorCCC>(RTy),
@@ -1001,53 +1002,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseExpr = Converted.get();
}
- LambdaScopeInfo *const CurLSI = getCurLambda();
- // If this is an implicit member reference and the overloaded
- // name refers to both static and non-static member functions
- // (i.e. BaseExpr is null) and if we are currently processing a lambda,
- // check if we should/can capture 'this'...
- // Keep this example in mind:
- // struct X {
- // void f(int) { }
- // static void f(double) { }
- //
- // int g() {
- // auto L = [=](auto a) {
- // return [](int i) {
- // return [=](auto b) {
- // f(b);
- // //f(decltype(a){});
- // };
- // };
- // };
- // auto M = L(0.0);
- // auto N = M(3);
- // N(5.32); // OK, must not error.
- // return 0;
- // }
- // };
- //
- if (!BaseExpr && CurLSI) {
- SourceLocation Loc = R.getNameLoc();
- if (SS.getRange().isValid())
- Loc = SS.getRange().getBegin();
- DeclContext *EnclosingFunctionCtx = CurContext->getParent()->getParent();
- // If the enclosing function is not dependent, then this lambda is
- // capture ready, so if we can capture this, do so.
- if (!EnclosingFunctionCtx->isDependentContext()) {
- // If the current lambda and all enclosing lambdas can capture 'this' -
- // then go ahead and capture 'this' (since our unresolved overload set
- // contains both static and non-static member functions).
- if (!CheckCXXThisCapture(Loc, /*Explcit*/false, /*Diagnose*/false))
- CheckCXXThisCapture(Loc);
- } else if (CurContext->isDependentContext()) {
- // ... since this is an implicit member reference, that might potentially
- // involve a 'this' capture, mark 'this' for potential capture in
- // enclosing lambdas.
- if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None)
- CurLSI->addPotentialThisCapture(Loc);
- }
- }
+
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
DeclarationName MemberName = MemberNameInfo.getName();
SourceLocation MemberLoc = MemberNameInfo.getLoc();
@@ -1836,7 +1791,9 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
MemberType = Context.getQualifiedType(MemberType, Combined);
}
- UnusedPrivateFields.remove(Field);
+ auto *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
+ if (!(CurMethod && CurMethod->isDefaulted()))
+ UnusedPrivateFields.remove(Field);
ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
FoundDecl, Field);
@@ -1848,8 +1805,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
if (getLangOpts().OpenMP && IsArrow &&
!CurContext->isDependentContext() &&
isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
- if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field))
- return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
+ if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) {
+ return getOpenMPCapturedExpr(PrivateCopy, VK, OK,
+ MemberNameInfo.getLoc());
+ }
}
return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 28581bad1a7a..6ed5047c35da 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -564,6 +564,13 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
BoxingMethod = StringWithUTF8StringMethod;
BoxedType = NSStringPointer;
+ // Transfer the nullability from method's return type.
+ Optional<NullabilityKind> Nullability =
+ BoxingMethod->getReturnType()->getNullability(Context);
+ if (Nullability)
+ BoxedType = Context.getAttributedType(
+ AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
+ BoxedType);
}
} else if (ValueType->isBuiltinType()) {
// The other types we support are numeric, char and BOOL/bool. We could also
@@ -2705,6 +2712,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
+ if (ReceiverType->isObjCIdType() && !isImplicit)
+ Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
+
// There's a somewhat weird interaction here where we assume that we
// won't actually have a method unless we also don't need to do some
// of the more detailed type-checking on the receiver.
@@ -4314,14 +4324,37 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType,
/// Look for an ObjCReclaimReturnedObject cast and destroy it.
static Expr *maybeUndoReclaimObject(Expr *e) {
- // For now, we just undo operands that are *immediately* reclaim
- // expressions, which prevents the vast majority of potential
- // problems here. To catch them all, we'd need to rebuild arbitrary
- // value-propagating subexpressions --- we can't reliably rebuild
- // in-place because of expression sharing.
- if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
- if (ice->getCastKind() == CK_ARCReclaimReturnedObject)
- return ice->getSubExpr();
+ Expr *curExpr = e, *prevExpr = nullptr;
+
+ // Walk down the expression until we hit an implicit cast of kind
+ // ARCReclaimReturnedObject or an Expr that is neither a Paren nor a Cast.
+ while (true) {
+ if (auto *pe = dyn_cast<ParenExpr>(curExpr)) {
+ prevExpr = curExpr;
+ curExpr = pe->getSubExpr();
+ continue;
+ }
+
+ if (auto *ce = dyn_cast<CastExpr>(curExpr)) {
+ if (auto *ice = dyn_cast<ImplicitCastExpr>(ce))
+ if (ice->getCastKind() == CK_ARCReclaimReturnedObject) {
+ if (!prevExpr)
+ return ice->getSubExpr();
+ if (auto *pe = dyn_cast<ParenExpr>(prevExpr))
+ pe->setSubExpr(ice->getSubExpr());
+ else
+ cast<CastExpr>(prevExpr)->setSubExpr(ice->getSubExpr());
+ return e;
+ }
+
+ prevExpr = curExpr;
+ curExpr = ce->getSubExpr();
+ continue;
+ }
+
+ // Break out of the loop if curExpr is neither a Paren nor a Cast.
+ break;
+ }
return e;
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 32024cb335dc..e4789cdf53bf 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -826,6 +826,34 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
return InitializableMembers - structDecl->hasFlexibleArrayMember();
}
+/// Determine whether Entity is an entity for which it is idiomatic to elide
+/// the braces in aggregate initialization.
+static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) {
+ // Recursive initialization of the one and only field within an aggregate
+ // class is considered idiomatic. This case arises in particular for
+ // initialization of std::array, where the C++ standard suggests the idiom of
+ //
+ // std::array<T, N> arr = {1, 2, 3};
+ //
+ // (where std::array is an aggregate struct containing a single array field.
+
+ // FIXME: Should aggregate initialization of a struct with a single
+ // base class and no members also suppress the warning?
+ if (Entity.getKind() != InitializedEntity::EK_Member || !Entity.getParent())
+ return false;
+
+ auto *ParentRD =
+ Entity.getParent()->getType()->castAs<RecordType>()->getDecl();
+ if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD))
+ if (CXXRD->getNumBases())
+ return false;
+
+ auto FieldIt = ParentRD->field_begin();
+ assert(FieldIt != ParentRD->field_end() &&
+ "no fields but have initializer for member?");
+ return ++FieldIt == ParentRD->field_end();
+}
+
/// Check whether the range of the initializer \p ParentIList from element
/// \p Index onwards can be used to initialize an object of type \p T. Update
/// \p Index to indicate how many elements of the list were consumed.
@@ -886,7 +914,9 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
}
// Complain about missing braces.
- if (T->isArrayType() || T->isRecordType()) {
+ if ((T->isArrayType() || T->isRecordType()) &&
+ !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
+ !isIdiomaticBraceElisionEntity(Entity)) {
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
diag::warn_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
@@ -1833,7 +1863,9 @@ void InitListChecker::CheckStructUnionTypes(
// worthwhile to skip over the rest of the initializer, though.
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
- bool CheckForMissingFields = true;
+ bool CheckForMissingFields =
+ !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
+
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
@@ -3531,12 +3563,13 @@ static OverloadingResult
ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
MultiExprArg Args,
OverloadCandidateSet &CandidateSet,
+ QualType DestType,
DeclContext::lookup_result Ctors,
OverloadCandidateSet::iterator &Best,
bool CopyInitializing, bool AllowExplicit,
bool OnlyListConstructors, bool IsListInit,
bool SecondStepOfCopyInit = false) {
- CandidateSet.clear();
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
for (NamedDecl *D : Ctors) {
auto Info = getConstructorInfo(D);
@@ -3587,6 +3620,50 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
}
}
+ // FIXME: Work around a bug in C++17 guaranteed copy elision.
+ //
+ // When initializing an object of class type T by constructor
+ // ([over.match.ctor]) or by list-initialization ([over.match.list])
+ // from a single expression of class type U, conversion functions of
+ // U that convert to the non-reference type cv T are candidates.
+ // Explicit conversion functions are only candidates during
+ // direct-initialization.
+ //
+ // Note: SecondStepOfCopyInit is only ever true in this case when
+ // evaluating whether to produce a C++98 compatibility warning.
+ if (S.getLangOpts().CPlusPlus17 && Args.size() == 1 &&
+ !SecondStepOfCopyInit) {
+ Expr *Initializer = Args[0];
+ auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl();
+ if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) {
+ const auto &Conversions = SourceRD->getVisibleConversionFunctions();
+ for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ D = D->getUnderlyingDecl();
+
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(D);
+
+ if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
+ ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit,
+ /*AllowResultConversion*/false);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ /*AllowResultConversion*/false);
+ }
+ }
+ }
+ }
+
// Perform overload resolution and return the result.
return CandidateSet.BestViableFunction(S, DeclLoc, Best);
}
@@ -3624,7 +3701,7 @@ static void TryConstructorInitialization(Sema &S,
return;
}
- // C++1z [dcl.init]p17:
+ // C++17 [dcl.init]p17:
// - If the initializer expression is a prvalue and the cv-unqualified
// version of the source type is the same class as the class of the
// destination, the initializer expression is used to initialize the
@@ -3633,7 +3710,7 @@ static void TryConstructorInitialization(Sema &S,
// class or delegating to another constructor from a mem-initializer.
// ObjC++: Lambda captured by the block in the lambda to block conversion
// should avoid copy elision.
- if (S.getLangOpts().CPlusPlus1z &&
+ if (S.getLangOpts().CPlusPlus17 &&
Entity.getKind() != InitializedEntity::EK_Base &&
Entity.getKind() != InitializedEntity::EK_Delegating &&
Entity.getKind() !=
@@ -3686,7 +3763,7 @@ static void TryConstructorInitialization(Sema &S,
// the first phase is omitted.
if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
- CandidateSet, Ctors, Best,
+ CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructor=*/true,
IsListInit);
@@ -3700,7 +3777,7 @@ static void TryConstructorInitialization(Sema &S,
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs,
- CandidateSet, Ctors, Best,
+ CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructors=*/false,
IsListInit);
@@ -3713,6 +3790,24 @@ static void TryConstructorInitialization(Sema &S,
return;
}
+ bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
+ // In C++17, ResolveConstructorOverload can select a conversion function
+ // instead of a constructor.
+ if (auto *CD = dyn_cast<CXXConversionDecl>(Best->Function)) {
+ // Add the user-defined conversion step that calls the conversion function.
+ QualType ConvType = CD->getConversionType();
+ assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) &&
+ "should not have selected this conversion function");
+ Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType,
+ HadMultipleCandidates);
+ if (!S.Context.hasSameType(ConvType, DestType))
+ Sequence.AddQualificationConversionStep(DestType, VK_RValue);
+ if (IsListInit)
+ Sequence.RewrapReferenceInitList(Entity.getType(), ILE);
+ return;
+ }
+
// C++11 [dcl.init]p6:
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
@@ -3741,7 +3836,6 @@ static void TryConstructorInitialization(Sema &S,
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
- bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddConstructorInitializationStep(
Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates,
IsListInit | IsInitListCopy, AsInitializerList);
@@ -3984,7 +4078,7 @@ static void TryListInitialization(Sema &S,
// value T(v); if a narrowing conversion is required to convert v to
// the underlying type of T, the program is ill-formed.
auto *ET = DestType->getAs<EnumType>();
- if (S.getLangOpts().CPlusPlus1z &&
+ if (S.getLangOpts().CPlusPlus17 &&
Kind.getKind() == InitializationKind::IK_DirectList &&
ET && ET->getDecl()->isFixed() &&
!S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
@@ -4087,7 +4181,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- CandidateSet.clear();
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
@@ -4173,7 +4267,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
- = CandidateSet.BestViableFunction(S, DeclLoc, Best, true))
+ = CandidateSet.BestViableFunction(S, DeclLoc, Best))
return Result;
FunctionDecl *Function = Best->Function;
@@ -4417,7 +4511,7 @@ static void TryReferenceInitializationCore(Sema &S,
RefRelationship == Sema::Ref_Related)) &&
((InitCategory.isXValue() && !isNonReferenceableGLValue(Initializer)) ||
(InitCategory.isPRValue() &&
- (S.getLangOpts().CPlusPlus1z || T2->isRecordType() ||
+ (S.getLangOpts().CPlusPlus17 || T2->isRecordType() ||
T2->isArrayType())))) {
ExprValueKind ValueKind = InitCategory.isXValue() ? VK_XValue : VK_RValue;
if (InitCategory.isPRValue() && T2->isRecordType()) {
@@ -4687,7 +4781,7 @@ static void TryUserDefinedConversion(Sema &S,
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
- CandidateSet.clear();
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
@@ -4766,7 +4860,7 @@ static void TryUserDefinedConversion(Sema &S,
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
- = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
+ = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
Sequence.SetOverloadFailure(
InitializationSequence::FK_UserConversionOverloadFailed,
Result);
@@ -4793,7 +4887,7 @@ static void TryUserDefinedConversion(Sema &S,
// copy-initialization.
// Note that this just performs a simple object copy from the temporary.
//
- // C++1z:
+ // C++17:
// - if the function is a constructor, the call is a prvalue of the
// cv-unqualified version of the destination type whose return object
// is initialized by the constructor. The call is used to
@@ -4802,7 +4896,7 @@ static void TryUserDefinedConversion(Sema &S,
// Therefore we need to do nothing further.
//
// FIXME: Mark this copy as extraneous.
- if (!S.getLangOpts().CPlusPlus1z)
+ if (!S.getLangOpts().CPlusPlus17)
Sequence.AddFinalCopy(DestType);
else if (DestType.hasQualifiers())
Sequence.AddQualificationConversionStep(DestType, VK_RValue);
@@ -4818,13 +4912,13 @@ static void TryUserDefinedConversion(Sema &S,
// The call is used to direct-initialize [...] the object that is the
// destination of the copy-initialization.
//
- // In C++1z, this does not call a constructor if we enter /17.6.1:
+ // In C++17, this does not call a constructor if we enter /17.6.1:
// - If the initializer expression is a prvalue and the cv-unqualified
// version of the source type is the same as the class of the
// destination [... do not make an extra copy]
//
// FIXME: Mark this copy as extraneous.
- if (!S.getLangOpts().CPlusPlus1z ||
+ if (!S.getLangOpts().CPlusPlus17 ||
Function->getReturnType()->isReferenceType() ||
!S.Context.hasSameUnqualifiedType(ConvType, DestType))
Sequence.AddFinalCopy(DestType);
@@ -5657,7 +5751,7 @@ static ExprResult CopyObject(Sema &S,
OverloadCandidateSet::iterator Best;
switch (ResolveConstructorOverload(
- S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
+ S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best,
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
/*SecondStepOfCopyInit=*/true)) {
@@ -5797,7 +5891,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
OverloadingResult OR = ResolveConstructorOverload(
- S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
+ S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best,
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
/*SecondStepOfCopyInit=*/true);
@@ -6328,6 +6422,10 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
if (!VD || !VD->hasLocalStorage())
return;
+ // __block variables are not moved implicitly.
+ if (VD->hasAttr<BlocksAttr>())
+ return;
+
QualType SourceType = VD->getType();
if (!SourceType->isRecordType())
return;
@@ -7535,8 +7633,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
- = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best,
- true);
+ = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl == OR_Deleted) {
S.NoteDeletedFunction(Best->Function);
} else {
@@ -8339,6 +8436,16 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
return Result;
}
+/// Determine whether RD is, or is derived from, a specialization of CTD.
+static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
+ ClassTemplateDecl *CTD) {
+ auto NotSpecialization = [&] (const CXXRecordDecl *Candidate) {
+ auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Candidate);
+ return !CTSD || !declaresSameEntity(CTSD->getSpecializedTemplate(), CTD);
+ };
+ return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization));
+}
+
QualType Sema::DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Inits) {
@@ -8405,7 +8512,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
OverloadCandidateSet::iterator Best;
auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
- Candidates.clear();
+ Candidates.clear(OverloadCandidateSet::CSK_Normal);
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (D->isInvalidDecl())
@@ -8483,6 +8590,17 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
break;
}
}
+ } else if (ListInit->getNumInits() == 1) {
+ // C++ [over.match.class.deduct]:
+ // As an exception, the first phase in [over.match.list] (considering
+ // initializer-list constructors) is omitted if the initializer list
+ // consists of a single expression of type cv U, where U is a
+ // specialization of C or a class derived from a specialization of C.
+ Expr *E = ListInit->getInit(0);
+ auto *RD = E->getType()->getAsCXXRecordDecl();
+ if (!isa<InitListExpr>(E) && RD &&
+ isOrIsDerivedFromSpecializationOf(RD, Template))
+ TryListConstructors = false;
}
if (TryListConstructors)
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 46f2ba376006..cbfc330ca60b 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -288,7 +288,9 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
Normal,
DefaultArgument,
DataMember,
- StaticDataMember
+ StaticDataMember,
+ InlineVariable,
+ VariableTemplate
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
@@ -303,6 +305,14 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
} else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
if (Var->getDeclContext()->isRecord())
Kind = StaticDataMember;
+ else if (Var->getMostRecentDecl()->isInline())
+ Kind = InlineVariable;
+ else if (Var->getDescribedVarTemplate())
+ Kind = VariableTemplate;
+ else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
+ if (!VTS->isExplicitSpecialization())
+ Kind = VariableTemplate;
+ }
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
}
@@ -343,6 +353,10 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
// -- the in-class initializers of class members
case DefaultArgument:
// -- default arguments appearing in class definitions
+ case InlineVariable:
+ // -- the initializers of inline variables
+ case VariableTemplate:
+ // -- the initializers of templated variables
return &ExprEvalContexts.back().getMangleNumberingContext(Context);
}
@@ -933,8 +947,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
PrevCaptureLoc = C->Loc, ++C) {
if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
if (C->Kind == LCK_StarThis)
- Diag(C->Loc, !getLangOpts().CPlusPlus1z
- ? diag::ext_star_this_lambda_capture_cxx1z
+ Diag(C->Loc, !getLangOpts().CPlusPlus17
+ ? diag::ext_star_this_lambda_capture_cxx17
: diag::warn_cxx14_compat_star_this_lambda_capture);
// C++11 [expr.prim.lambda]p8:
@@ -948,17 +962,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- // C++1z [expr.prim.lambda]p8:
- // If a lambda-capture includes a capture-default that is =, each
- // simple-capture of that lambda-capture shall be of the form "&
- // identifier" or "* this". [ Note: The form [&,this] is redundant but
- // accepted for compatibility with ISO C++14. --end note ]
- if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) {
- Diag(C->Loc, diag::err_this_capture_with_copy_default)
- << FixItHint::CreateRemoval(
- SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
- continue;
- }
+ // C++2a [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is =,
+ // each simple-capture of that lambda-capture shall be of the form
+ // "&identifier", "this", or "* this". [ Note: The form [&,this] is
+ // redundant but accepted for compatibility with ISO C++14. --end note ]
+ if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
+ Diag(C->Loc, !getLangOpts().CPlusPlus2a
+ ? diag::ext_equals_this_lambda_capture_cxx2a
+ : diag::warn_cxx17_compat_equals_this_lambda_capture);
// C++11 [expr.prim.lambda]p12:
// If this is captured by a local lambda expression, its nearest
@@ -1276,7 +1288,7 @@ static void addFunctionPointerConversion(Sema &S,
ConvTy,
ConvTSI,
/*isInline=*/true, /*isExplicit=*/false,
- /*isConstexpr=*/S.getLangOpts().CPlusPlus1z,
+ /*isConstexpr=*/S.getLangOpts().CPlusPlus17,
CallOperator->getBody()->getLocEnd());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
@@ -1469,6 +1481,9 @@ void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture &From) {
if (CaptureHasSideEffects(From))
return;
+ if (From.isVLATypeCapture())
+ return;
+
auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture);
if (From.isThisCapture())
diag << "'this'";
@@ -1596,7 +1611,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// If the lambda expression's call operator is not explicitly marked constexpr
// and we are not in a dependent context, analyze the call operator to infer
// its constexpr-ness, suppressing diagnostics while doing so.
- if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() &&
+ if (getLangOpts().CPlusPlus17 && !CallOperator->isInvalidDecl() &&
!CallOperator->isConstexpr() &&
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 85596ed52e9d..d3f91a4e273d 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -88,13 +88,15 @@ namespace {
/// A collection of using directives, as used by C++ unqualified
/// lookup.
class UnqualUsingDirectiveSet {
+ Sema &SemaRef;
+
typedef SmallVector<UnqualUsingEntry, 8> ListTy;
ListTy list;
llvm::SmallPtrSet<DeclContext*, 8> visited;
public:
- UnqualUsingDirectiveSet() {}
+ UnqualUsingDirectiveSet(Sema &SemaRef) : SemaRef(SemaRef) {}
void visitScopeChain(Scope *S, Scope *InnermostFileScope) {
// C++ [namespace.udir]p1:
@@ -113,7 +115,8 @@ namespace {
visit(Ctx, Ctx);
} else if (!Ctx || Ctx->isFunctionOrMethod()) {
for (auto *I : S->using_directives())
- visit(I, InnermostFileDC);
+ if (SemaRef.isVisible(I))
+ visit(I, InnermostFileDC);
}
}
}
@@ -152,7 +155,7 @@ namespace {
while (true) {
for (auto UD : DC->using_directives()) {
DeclContext *NS = UD->getNominatedNamespace();
- if (visited.insert(NS).second) {
+ if (SemaRef.isVisible(UD) && visited.insert(NS).second) {
addUsingDirective(UD, EffectiveDC);
queue.push_back(NS);
}
@@ -1031,7 +1034,8 @@ struct FindLocalExternScope {
FindLocalExternScope(LookupResult &R)
: R(R), OldFindLocalExtern(R.getIdentifierNamespace() &
Decl::IDNS_LocalExtern) {
- R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary);
+ R.setFindLocalExtern(R.getIdentifierNamespace() &
+ (Decl::IDNS_Ordinary | Decl::IDNS_NonMemberOperator));
}
void restore() {
R.setFindLocalExtern(OldFindLocalExtern);
@@ -1084,7 +1088,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// }
// }
//
- UnqualUsingDirectiveSet UDirs;
+ UnqualUsingDirectiveSet UDirs(*this);
bool VisitedUsingDirectives = false;
bool LeftStartingScope = false;
DeclContext *OutsideOfTemplateParamDC = nullptr;
@@ -1370,7 +1374,7 @@ static Module *getDefiningModule(Sema &S, Decl *Entity) {
// Walk up to the containing context. That might also have been instantiated
// from a template.
- DeclContext *Context = Entity->getDeclContext();
+ DeclContext *Context = Entity->getLexicalDeclContext();
if (Context->isFileContext())
return S.getOwningModule(Entity);
return getDefiningModule(S, cast<Decl>(Context));
@@ -1608,11 +1612,39 @@ bool Sema::isVisibleSlow(const NamedDecl *D) {
}
bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) {
+ // FIXME: If there are both visible and hidden declarations, we need to take
+ // into account whether redeclaration is possible. Example:
+ //
+ // Non-imported module:
+ // int f(T); // #1
+ // Some TU:
+ // static int f(U); // #2, not a redeclaration of #1
+ // int f(T); // #3, finds both, should link with #1 if T != U, but
+ // // with #2 if T == U; neither should be ambiguous.
for (auto *D : R) {
if (isVisible(D))
return true;
+ assert(D->isExternallyDeclarable() &&
+ "should not have hidden, non-externally-declarable result here");
}
- return New->isExternallyVisible();
+
+ // This function is called once "New" is essentially complete, but before a
+ // previous declaration is attached. We can't query the linkage of "New" in
+ // general, because attaching the previous declaration can change the
+ // linkage of New to match the previous declaration.
+ //
+ // However, because we've just determined that there is no *visible* prior
+ // declaration, we can compute the linkage here. There are two possibilities:
+ //
+ // * This is not a redeclaration; it's safe to compute the linkage now.
+ //
+ // * This is a redeclaration of a prior declaration that is externally
+ // redeclarable. In that case, the linkage of the declaration is not
+ // changed by attaching the prior declaration, because both are externally
+ // declarable (and thus ExternalLinkage or VisibleNoLinkage).
+ //
+ // FIXME: This is subtle and fragile.
+ return New->isExternallyDeclarable();
}
/// \brief Retrieve the visible declaration corresponding to D, if any.
@@ -1839,22 +1871,19 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
DeclContext *StartDC) {
assert(StartDC->isFileContext() && "start context is not a file context");
- DeclContext::udir_range UsingDirectives = StartDC->using_directives();
- if (UsingDirectives.begin() == UsingDirectives.end()) return false;
+ // We have not yet looked into these namespaces, much less added
+ // their "using-children" to the queue.
+ SmallVector<NamespaceDecl*, 8> Queue;
// We have at least added all these contexts to the queue.
llvm::SmallPtrSet<DeclContext*, 8> Visited;
Visited.insert(StartDC);
- // We have not yet looked into these namespaces, much less added
- // their "using-children" to the queue.
- SmallVector<NamespaceDecl*, 8> Queue;
-
// We have already looked into the initial namespace; seed the queue
// with its using-children.
- for (auto *I : UsingDirectives) {
+ for (auto *I : StartDC->using_directives()) {
NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace();
- if (Visited.insert(ND).second)
+ if (S.isVisible(I) && Visited.insert(ND).second)
Queue.push_back(ND);
}
@@ -1902,7 +1931,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
for (auto I : ND->using_directives()) {
NamespaceDecl *Nom = I->getNominatedNamespace();
- if (Visited.insert(Nom).second)
+ if (S.isVisible(I) && Visited.insert(Nom).second)
Queue.push_back(Nom);
}
}
@@ -3121,7 +3150,7 @@ Sema::LiteralOperatorLookupResult
Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
ArrayRef<QualType> ArgTys,
bool AllowRaw, bool AllowTemplate,
- bool AllowStringTemplate) {
+ bool AllowStringTemplate, bool DiagnoseMissing) {
LookupName(R, S);
assert(R.getResultKind() != LookupResult::Ambiguous &&
"literal operator lookup can't be ambiguous");
@@ -3222,11 +3251,15 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
return LOLR_StringTemplate;
// Didn't find anything we could use.
- Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator)
- << R.getLookupName() << (int)ArgTys.size() << ArgTys[0]
- << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw
- << (AllowTemplate || AllowStringTemplate);
- return LOLR_Error;
+ if (DiagnoseMissing) {
+ Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator)
+ << R.getLookupName() << (int)ArgTys.size() << ArgTys[0]
+ << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw
+ << (AllowTemplate || AllowStringTemplate);
+ return LOLR_Error;
+ }
+
+ return LOLR_ErrorNoDiagnostic;
}
void ADLResult::insert(NamedDecl *New) {
@@ -3316,16 +3349,24 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
continue;
}
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ auto *Underlying = D;
+ if (auto *USD = dyn_cast<UsingShadowDecl>(D))
+ Underlying = USD->getTargetDecl();
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D))
+ if (!isa<FunctionDecl>(Underlying) &&
+ !isa<FunctionTemplateDecl>(Underlying))
continue;
- if (!isVisible(D) && !(D = findAcceptableDecl(*this, D)))
- continue;
+ if (!isVisible(D)) {
+ D = findAcceptableDecl(*this, D);
+ if (!D)
+ continue;
+ if (auto *USD = dyn_cast<UsingShadowDecl>(D))
+ Underlying = USD->getTargetDecl();
+ }
- Result.insert(D);
+ // FIXME: Preserve D as the FoundDecl.
+ Result.insert(Underlying);
}
}
}
@@ -3507,6 +3548,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
for (auto I : Ctx->using_directives()) {
+ if (!Result.getSema().isVisible(I))
+ continue;
LookupVisibleDecls(I->getNominatedNamespace(), Result,
QualifiedNameLookup, InBaseClass, Consumer, Visited,
IncludeDependentBases);
@@ -3634,8 +3677,10 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
!Visited.alreadyVisitedContext(S->getEntity())) ||
(S->getEntity())->isFunctionOrMethod()) {
FindLocalExternScope FindLocals(Result);
- // Walk through the declarations in this Scope.
- for (auto *D : S->decls()) {
+ // Walk through the declarations in this Scope. The consumer might add new
+ // decls to the scope as part of deserialization, so make a copy first.
+ SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end());
+ for (Decl *D : ScopeDecls) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
@@ -3713,7 +3758,7 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
// Determine the set of using directives available during
// unqualified name lookup.
Scope *Initial = S;
- UnqualUsingDirectiveSet UDirs;
+ UnqualUsingDirectiveSet UDirs(*this);
if (getLangOpts().CPlusPlus) {
// Find the first namespace or translation-unit scope.
while (S && !isNamespaceOrTranslationUnitScope(S))
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index bfb0071a54f9..ea5b1da46f32 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -1290,6 +1290,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// An abstract type is as bad as an incomplete type.
CompleteTypeErr = true;
}
+ if (!CompleteTypeErr) {
+ const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>();
+ if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) {
+ Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar)
+ << PropertyIvarType;
+ CompleteTypeErr = true; // suppress later diagnostics about the ivar
+ }
+ }
if (CompleteTypeErr)
Ivar->setInvalidDecl();
ClassImpDecl->addDecl(Ivar);
@@ -1599,7 +1607,11 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
// meaningless for readonly properties, so don't diagnose if the
// atomic property is 'readonly'.
checkAtomicPropertyMismatch(*this, SuperProperty, Property, false);
- if (Property->getSetterName() != SuperProperty->getSetterName()) {
+ // Readonly properties from protocols can be implemented as "readwrite"
+ // with a custom setter name.
+ if (Property->getSetterName() != SuperProperty->getSetterName() &&
+ !(SuperProperty->isReadOnly() &&
+ isa<ObjCProtocolDecl>(SuperProperty->getDeclContext()))) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "setter" << inheritedName;
Diag(SuperProperty->getLocation(), diag::note_property_declare);
@@ -1895,7 +1907,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
/* property = */ Prop->getIdentifier(),
/* ivar = */ Prop->getDefaultSynthIvarName(Context),
Prop->getLocation(), Prop->getQueryKind()));
- if (PIDecl) {
+ if (PIDecl && !Prop->isUnavailable()) {
Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
}
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 1ae6f9d6c19c..b34bb3388d71 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -22,27 +22,36 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/PointerEmbeddedInt.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Stack of data-sharing attributes for variables
//===----------------------------------------------------------------------===//
+static Expr *CheckMapClauseExpressionBase(
+ Sema &SemaRef, Expr *E,
+ OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
+ OpenMPClauseKind CKind, bool NoDiagnose);
+
namespace {
/// \brief Default data sharing attributes, which can be applied to directive.
enum DefaultDataSharingAttributes {
DSA_unspecified = 0, /// \brief Data sharing attribute not specified.
DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'.
- DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'.
+ DSA_shared = 1 << 1, /// \brief Default data sharing attribute 'shared'.
+};
+
+/// Attributes of the defaultmap clause.
+enum DefaultMapAttributes {
+ DMA_unspecified, /// Default mapping is not specified.
+ DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'.
};
/// \brief Stack for tracking declarations used in OpenMP directives and
@@ -55,7 +64,11 @@ public:
Expr *RefExpr = nullptr;
DeclRefExpr *PrivateCopy = nullptr;
SourceLocation ImplicitDSALoc;
- DSAVarData() {}
+ DSAVarData() = default;
+ DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, Expr *RefExpr,
+ DeclRefExpr *PrivateCopy, SourceLocation ImplicitDSALoc)
+ : DKind(DKind), CKind(CKind), RefExpr(RefExpr),
+ PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {}
};
typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>
OperatorOffsetTy;
@@ -84,14 +97,32 @@ private:
CriticalsWithHintsTy;
typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>
DoacrossDependMapTy;
+ struct ReductionData {
+ typedef llvm::PointerEmbeddedInt<BinaryOperatorKind, 16> BOKPtrType;
+ SourceRange ReductionRange;
+ llvm::PointerUnion<const Expr *, BOKPtrType> ReductionOp;
+ ReductionData() = default;
+ void set(BinaryOperatorKind BO, SourceRange RR) {
+ ReductionRange = RR;
+ ReductionOp = BO;
+ }
+ void set(const Expr *RefExpr, SourceRange RR) {
+ ReductionRange = RR;
+ ReductionOp = RefExpr;
+ }
+ };
+ typedef llvm::DenseMap<ValueDecl *, ReductionData> DeclReductionMapTy;
struct SharingMapTy final {
DeclSAMapTy SharingMap;
+ DeclReductionMapTy ReductionMap;
AlignedMapTy AlignedMap;
MappedExprComponentsTy MappedExprComponents;
LoopControlVariablesMapTy LCVMap;
DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
SourceLocation DefaultAttrLoc;
+ DefaultMapAttributes DefaultMapAttr = DMA_unspecified;
+ SourceLocation DefaultMapAttrLoc;
OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
@@ -108,11 +139,13 @@ private:
bool CancelRegion = false;
unsigned AssociatedLoops = 1;
SourceLocation InnerTeamsRegionLoc;
+ /// Reference to the taskgroup task_reduction reference expression.
+ Expr *TaskgroupReductionRef = nullptr;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
ConstructLoc(Loc) {}
- SharingMapTy() {}
+ SharingMapTy() = default;
};
typedef SmallVector<SharingMapTy, 4> StackTy;
@@ -145,6 +178,10 @@ public:
explicit DSAStackTy(Sema &S) : SemaRef(S) {}
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
+ OpenMPClauseKind getClauseParsingMode() const {
+ assert(isClauseParsingMode() && "Must be in clause parsing mode.");
+ return ClauseKindMode;
+ }
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
bool isForceVarCapturing() const { return ForceCapturing; }
@@ -221,6 +258,39 @@ public:
void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
DeclRefExpr *PrivateCopy = nullptr);
+ /// Adds additional information for the reduction items with the reduction id
+ /// represented as an operator.
+ void addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ BinaryOperatorKind BOK);
+ /// Adds additional information for the reduction items with the reduction id
+ /// represented as reduction identifier.
+ void addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ const Expr *ReductionRef);
+ /// Returns the location and reduction operation from the innermost parent
+ /// region for the given \p D.
+ DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ BinaryOperatorKind &BOK,
+ Expr *&TaskgroupDescriptor);
+ /// Returns the location and reduction operation from the innermost parent
+ /// region for the given \p D.
+ DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ const Expr *&ReductionRef,
+ Expr *&TaskgroupDescriptor);
+ /// Return reduction reference expression for the current taskgroup.
+ Expr *getTaskgroupReductionRef() const {
+ assert(Stack.back().first.back().Directive == OMPD_taskgroup &&
+ "taskgroup reference expression requested for non taskgroup "
+ "directive.");
+ return Stack.back().first.back().TaskgroupReductionRef;
+ }
+ /// Checks if the given \p VD declaration is actually a taskgroup reduction
+ /// descriptor variable at the \p Level of OpenMP regions.
+ bool isTaskgroupReductionRef(ValueDecl *VD, unsigned Level) const {
+ return Stack.back().first[Level].TaskgroupReductionRef &&
+ cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef)
+ ->getDecl() == VD;
+ }
+
/// \brief Returns data sharing attributes from top of the stack for the
/// specified declaration.
DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
@@ -264,6 +334,11 @@ public:
OpenMPDirectiveKind getCurrentDirective() const {
return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
}
+ /// \brief Returns directive kind at specified level.
+ OpenMPDirectiveKind getDirective(unsigned Level) const {
+ assert(!isStackEmpty() && "No directive at specified level.");
+ return Stack.back().first[Level].Directive;
+ }
/// \brief Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
if (isStackEmpty() || Stack.back().first.size() == 1)
@@ -283,6 +358,12 @@ public:
Stack.back().first.back().DefaultAttr = DSA_shared;
Stack.back().first.back().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;
+ }
DefaultDataSharingAttributes getDefaultDSA() const {
return isStackEmpty() ? DSA_unspecified
@@ -292,6 +373,17 @@ public:
return isStackEmpty() ? SourceLocation()
: Stack.back().first.back().DefaultAttrLoc;
}
+ DefaultMapAttributes getDefaultDMA() const {
+ return isStackEmpty() ? DMA_unspecified
+ : Stack.back().first.back().DefaultMapAttr;
+ }
+ DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
+ return Stack.back().first[Level].DefaultMapAttr;
+ }
+ SourceLocation getDefaultDMALocation() const {
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().DefaultMapAttrLoc;
+ }
/// \brief Checks if the specified variable is a threadprivate.
bool isThreadPrivate(VarDecl *D) {
@@ -479,7 +571,25 @@ bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
}
} // namespace
+static Expr *getExprAsWritten(Expr *E) {
+ if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E))
+ E = ExprTemp->getSubExpr();
+
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
+ E = MTE->GetTemporaryExpr();
+
+ while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = Binder->getSubExpr();
+
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExprAsWritten();
+ return E->IgnoreParens();
+}
+
static ValueDecl *getCanonicalDecl(ValueDecl *D) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D))
+ if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
+ D = ME->getMemberDecl();
auto *VD = dyn_cast<VarDecl>(D);
auto *FD = dyn_cast<FieldDecl>(D);
if (VD != nullptr) {
@@ -522,7 +632,6 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
return DVar;
}
- DVar.DKind = Iter->Directive;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.1]
// Variables with automatic storage duration that are declared in a scope
@@ -533,6 +642,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
return DVar;
}
+ DVar.DKind = Iter->Directive;
// Explicitly specified attributes and local variables with predetermined
// attributes.
if (Iter->SharingMap.count(D)) {
@@ -691,24 +801,6 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
}
}
-bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
- D = D->getCanonicalDecl();
- if (!isStackEmpty() && Stack.back().first.size() > 1) {
- reverse_iterator I = Iter, E = Stack.back().first.rend();
- Scope *TopScope = nullptr;
- while (I != E && !isParallelOrTaskRegion(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;
- }
- return false;
-}
-
/// \brief Build a variable declaration for OpenMP loop iteration variable.
static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
StringRef Name, const AttrVec *Attrs = nullptr) {
@@ -736,6 +828,130 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty,
VK_LValue);
}
+void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ BinaryOperatorKind BOK) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ assert(
+ Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ "Additional reduction info may be specified only for reduction items.");
+ auto &ReductionData = Stack.back().first.back().ReductionMap[D];
+ assert(ReductionData.ReductionRange.isInvalid() &&
+ Stack.back().first.back().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;
+ if (!TaskgroupReductionRef) {
+ auto *VD = buildVarDecl(SemaRef, SR.getBegin(),
+ SemaRef.Context.VoidPtrTy, ".task_red.");
+ TaskgroupReductionRef =
+ buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin());
+ }
+}
+
+void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR,
+ const Expr *ReductionRef) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ assert(
+ Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ "Additional reduction info may be specified only for reduction items.");
+ auto &ReductionData = Stack.back().first.back().ReductionMap[D];
+ assert(ReductionData.ReductionRange.isInvalid() &&
+ Stack.back().first.back().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;
+ if (!TaskgroupReductionRef) {
+ auto *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy,
+ ".task_red.");
+ TaskgroupReductionRef =
+ buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin());
+ }
+}
+
+DSAStackTy::DSAVarData
+DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ BinaryOperatorKind &BOK,
+ Expr *&TaskgroupDescriptor) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
+ if (Stack.back().first.empty())
+ return DSAVarData();
+ for (auto I = std::next(Stack.back().first.rbegin(), 1),
+ E = Stack.back().first.rend();
+ I != E; std::advance(I, 1)) {
+ auto &Data = I->SharingMap[D];
+ if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
+ continue;
+ auto &ReductionData = I->ReductionMap[D];
+ if (!ReductionData.ReductionOp ||
+ ReductionData.ReductionOp.is<const Expr *>())
+ return DSAVarData();
+ SR = ReductionData.ReductionRange;
+ BOK = ReductionData.ReductionOp.get<ReductionData::BOKPtrType>();
+ assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
+ "expression for the descriptor is not "
+ "set.");
+ TaskgroupDescriptor = I->TaskgroupReductionRef;
+ return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc);
+ }
+ return DSAVarData();
+}
+
+DSAStackTy::DSAVarData
+DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR,
+ const Expr *&ReductionRef,
+ Expr *&TaskgroupDescriptor) {
+ D = getCanonicalDecl(D);
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
+ if (Stack.back().first.empty())
+ return DSAVarData();
+ for (auto I = std::next(Stack.back().first.rbegin(), 1),
+ E = Stack.back().first.rend();
+ I != E; std::advance(I, 1)) {
+ auto &Data = I->SharingMap[D];
+ if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
+ continue;
+ auto &ReductionData = I->ReductionMap[D];
+ if (!ReductionData.ReductionOp ||
+ !ReductionData.ReductionOp.is<const Expr *>())
+ return DSAVarData();
+ SR = ReductionData.ReductionRange;
+ ReductionRef = ReductionData.ReductionOp.get<const Expr *>();
+ assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
+ "expression for the descriptor is not "
+ "set.");
+ TaskgroupDescriptor = I->TaskgroupReductionRef;
+ return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc);
+ }
+ return DSAVarData();
+}
+
+bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
+ D = D->getCanonicalDecl();
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ reverse_iterator I = Iter, E = Stack.back().first.rend();
+ Scope *TopScope = nullptr;
+ while (I != E && !isParallelOrTaskRegion(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;
+ }
+ return false;
+}
+
DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
D = getCanonicalDecl(D);
DSAVarData DVar;
@@ -759,6 +975,12 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
return DVar;
+ } else if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
+ DVar.RefExpr = buildDeclRefExpr(
+ SemaRef, VD, D->getType().getNonReferenceType(),
+ VD->getAttr<OMPThreadPrivateDeclAttr>()->getLocation());
+ DVar.CKind = OMPC_threadprivate;
+ addDSA(D, DVar.RefExpr, OMPC_threadprivate);
}
if (isStackEmpty())
@@ -811,16 +1033,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
// Explicitly specified attributes and local variables with predetermined
// attributes.
- auto StartI = std::next(Stack.back().first.rbegin());
+ auto I = Stack.back().first.rbegin();
auto EndI = Stack.back().first.rend();
- if (FromParent && StartI != EndI)
- StartI = std::next(StartI);
- auto I = std::prev(StartI);
+ if (FromParent && I != EndI)
+ std::advance(I, 1);
if (I->SharingMap.count(D)) {
DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer();
DVar.PrivateCopy = I->SharingMap[D].PrivateCopy;
DVar.CKind = I->SharingMap[D].Attributes;
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
+ DVar.DKind = I->Directive;
}
return DVar;
@@ -836,7 +1058,7 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
auto StartI = Stack.back().first.rbegin();
auto EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
- StartI = std::next(StartI);
+ std::advance(StartI, 1);
return getDSA(StartI, D);
}
@@ -848,16 +1070,16 @@ DSAStackTy::hasDSA(ValueDecl *D,
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
- auto I = (FromParent && Stack.back().first.size() > 1)
- ? std::next(Stack.back().first.rbegin())
- : Stack.back().first.rbegin();
+ auto I = Stack.back().first.rbegin();
auto EndI = Stack.back().first.rend();
- while (std::distance(I, EndI) > 1) {
+ if (FromParent && I != EndI)
std::advance(I, 1);
+ for (; I != EndI; std::advance(I, 1)) {
if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive))
continue;
- DSAVarData DVar = getDSA(I, D);
- if (CPred(DVar.CKind))
+ auto NewI = I;
+ DSAVarData DVar = getDSA(NewI, D);
+ if (I == NewI && CPred(DVar.CKind))
return DVar;
}
return {};
@@ -870,21 +1092,20 @@ DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.back().first.rbegin());
+ auto StartI = Stack.back().first.rbegin();
auto EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
- StartI = std::next(StartI);
+ std::advance(StartI, 1);
if (StartI == EndI || !DPred(StartI->Directive))
return {};
- DSAVarData DVar = getDSA(StartI, D);
- return CPred(DVar.CKind) ? DVar : DSAVarData();
+ auto NewI = StartI;
+ DSAVarData DVar = getDSA(NewI, D);
+ return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData();
}
bool DSAStackTy::hasExplicitDSA(
ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
unsigned Level, bool NotLastprivate) {
- if (CPred(ClauseKindMode))
- return true;
if (isStackEmpty())
return false;
D = getCanonicalDecl(D);
@@ -952,6 +1173,7 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
bool IsByRef = true;
// Find the directive that is associated with the provided scope.
+ D = cast<ValueDecl>(D->getCanonicalDecl());
auto Ty = D->getType();
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
@@ -1057,8 +1279,13 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
// reference except if it is a pointer that is dereferenced somehow.
IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection);
} else {
- // By default, all the data that has a scalar type is mapped by copy.
- IsByRef = !Ty->isScalarType();
+ // By default, all the data that has a scalar type is mapped by copy
+ // (except for reduction variables).
+ IsByRef =
+ !Ty->isScalarType() ||
+ DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar ||
+ DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_reduction; }, Level);
}
}
@@ -1087,6 +1314,17 @@ unsigned Sema::getOpenMPNestingLevel() const {
return DSAStack->getNestingLevel();
}
+bool Sema::isInOpenMPTargetExecutionDirective() const {
+ return (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) &&
+ !DSAStack->isClauseParsingMode()) ||
+ DSAStack->hasDirective(
+ [](OpenMPDirectiveKind K, const DeclarationNameInfo &,
+ SourceLocation) -> bool {
+ return isOpenMPTargetExecutionDirective(K);
+ },
+ false);
+}
+
VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
@@ -1099,18 +1337,8 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
// inserted here once support for 'declare target' is added.
//
auto *VD = dyn_cast<VarDecl>(D);
- if (VD && !VD->hasLocalStorage()) {
- if (DSAStack->getCurrentDirective() == OMPD_target &&
- !DSAStack->isClauseParsingMode())
- return VD;
- if (DSAStack->hasDirective(
- [](OpenMPDirectiveKind K, const DeclarationNameInfo &,
- SourceLocation) -> bool {
- return isOpenMPTargetExecutionDirective(K);
- },
- false))
- return VD;
- }
+ if (VD && !VD->hasLocalStorage() && isInOpenMPTargetExecutionDirective())
+ return VD;
if (DSAStack->getCurrentDirective() != OMPD_unknown &&
(!DSAStack->isClauseParsingMode() ||
@@ -1133,10 +1361,59 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
return nullptr;
}
+void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
+ unsigned Level) const {
+ SmallVector<OpenMPDirectiveKind, 4> Regions;
+ getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level));
+ FunctionScopesIndex -= Regions.size();
+}
+
bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
return DSAStack->hasExplicitDSA(
- D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level);
+ D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; },
+ Level) ||
+ (DSAStack->isClauseParsingMode() &&
+ DSAStack->getClauseParsingMode() == OMPC_private) ||
+ // Consider taskgroup reduction descriptor variable a private to avoid
+ // possible capture in the region.
+ (DSAStack->hasExplicitDirective(
+ [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; },
+ Level) &&
+ DSAStack->isTaskgroupReductionRef(D, Level));
+}
+
+void Sema::setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level) {
+ assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ D = getCanonicalDecl(D);
+ OpenMPClauseKind OMPC = OMPC_unknown;
+ for (unsigned I = DSAStack->getNestingLevel() + 1; I > Level; --I) {
+ const unsigned NewLevel = I - 1;
+ if (DSAStack->hasExplicitDSA(D,
+ [&OMPC](const OpenMPClauseKind K) {
+ if (isOpenMPPrivate(K)) {
+ OMPC = K;
+ return true;
+ }
+ return false;
+ },
+ NewLevel))
+ break;
+ if (DSAStack->checkMappableExprComponentListsForDeclAtLevel(
+ D, NewLevel,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind) { return true; })) {
+ OMPC = OMPC_map;
+ break;
+ }
+ if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
+ NewLevel)) {
+ OMPC = OMPC_firstprivate;
+ break;
+ }
+ }
+ if (OMPC != OMPC_unknown)
+ FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC));
}
bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level) {
@@ -1249,7 +1526,7 @@ public:
explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
- if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
+ if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) {
return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
SemaRef.getCurScope());
}
@@ -1568,7 +1845,9 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {
bool ErrorFound;
CapturedStmt *CS;
llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
+ llvm::SmallVector<Expr *, 8> ImplicitMap;
llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA;
+ llvm::DenseSet<ValueDecl *> ImplicitDeclarations;
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
@@ -1576,13 +1855,18 @@ public:
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->isLocalVarDecl() && !CS->capturesVariable(VD))
+ if (VD->hasLocalStorage() && !CS->capturesVariable(VD))
return;
auto DVar = Stack->getTopDSA(VD, false);
// Check if the variable has explicit DSA set and stop analysis if it so.
- if (DVar.RefExpr)
+ if (DVar.RefExpr || !ImplicitDeclarations.insert(VD).second)
+ return;
+
+ // Skip internally declared static variables.
+ if (VD->hasGlobalStorage() && !CS->capturesVariable(VD))
return;
auto ELoc = E->getExprLoc();
@@ -1598,6 +1882,46 @@ public:
return;
}
+ if (isOpenMPTargetExecutionDirective(DKind) &&
+ !Stack->isLoopControlVariable(VD).first) {
+ if (!Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents,
+ OpenMPClauseKind) {
+ // Variable is used if it has been marked as an array, array
+ // section or the variable iself.
+ return StackComponents.size() == 1 ||
+ std::all_of(
+ std::next(StackComponents.rbegin()),
+ StackComponents.rend(),
+ [](const OMPClauseMappableExprCommon::
+ MappableComponent &MC) {
+ return MC.getAssociatedDeclaration() ==
+ nullptr &&
+ (isa<OMPArraySectionExpr>(
+ MC.getAssociatedExpression()) ||
+ isa<ArraySubscriptExpr>(
+ MC.getAssociatedExpression()));
+ });
+ })) {
+ bool IsFirstprivate = false;
+ // By default lambdas are captured as firstprivates.
+ if (const auto *RD =
+ VD->getType().getNonReferenceType()->getAsCXXRecordDecl())
+ IsFirstprivate = RD->isLambda();
+ IsFirstprivate =
+ IsFirstprivate ||
+ (VD->getType().getNonReferenceType()->isScalarType() &&
+ Stack->getDefaultDMA() != DMA_tofrom_scalar);
+ if (IsFirstprivate)
+ ImplicitFirstprivate.emplace_back(E);
+ else
+ ImplicitMap.emplace_back(E);
+ return;
+ }
+ }
+
// OpenMP [2.9.3.6, Restrictions, p.2]
// A list item that appears in a reduction clause of the innermost
// enclosing worksharing or parallel construct may not be accessed in an
@@ -1608,7 +1932,7 @@ public:
return isOpenMPParallelDirective(K) ||
isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
},
- false);
+ /*FromParent=*/true);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
ErrorFound = true;
SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
@@ -1627,40 +1951,103 @@ public:
if (E->isTypeDependent() || E->isValueDependent() ||
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
+ auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) {
- if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
- auto DVar = Stack->getTopDSA(FD, false);
- // Check if the variable has explicit DSA set and stop analysis if it
- // so.
- if (DVar.RefExpr)
- return;
+ if (!FD)
+ return;
+ auto DVar = Stack->getTopDSA(FD, false);
+ // Check if the variable has explicit DSA set and stop analysis if it
+ // so.
+ if (DVar.RefExpr || !ImplicitDeclarations.insert(FD).second)
+ return;
- auto ELoc = E->getExprLoc();
- auto DKind = Stack->getCurrentDirective();
- // OpenMP [2.9.3.6, Restrictions, p.2]
- // A list item that appears in a reduction clause of the innermost
- // enclosing worksharing or parallel construct may not be accessed in
- // an explicit task.
- DVar = Stack->hasInnermostDSA(
- FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K) ||
- isOpenMPTeamsDirective(K);
- },
- false);
- if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
- ErrorFound = true;
- SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
- ReportOriginalDSA(SemaRef, Stack, FD, DVar);
+ if (isOpenMPTargetExecutionDirective(DKind) &&
+ !Stack->isLoopControlVariable(FD).first &&
+ !Stack->checkMappableExprComponentListsForDecl(
+ FD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents,
+ OpenMPClauseKind) {
+ return isa<CXXThisExpr>(
+ cast<MemberExpr>(
+ StackComponents.back().getAssociatedExpression())
+ ->getBase()
+ ->IgnoreParens());
+ })) {
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
+ // A bit-field cannot appear in a map clause.
+ //
+ if (FD->isBitField())
return;
- }
+ ImplicitMap.emplace_back(E);
+ return;
+ }
+
+ auto ELoc = E->getExprLoc();
+ // OpenMP [2.9.3.6, Restrictions, p.2]
+ // A list item that appears in a reduction clause of the innermost
+ // enclosing worksharing or parallel construct may not be accessed in
+ // an explicit task.
+ DVar = Stack->hasInnermostDSA(
+ FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
+ },
+ /*FromParent=*/true);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
+ ErrorFound = true;
+ SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
+ ReportOriginalDSA(SemaRef, Stack, FD, DVar);
+ return;
+ }
- // Define implicit data-sharing attributes for task.
- DVar = Stack->getImplicitDSA(FD, false);
- if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
- !Stack->isLoopControlVariable(FD).first)
- ImplicitFirstprivate.push_back(E);
+ // Define implicit data-sharing attributes for task.
+ DVar = Stack->getImplicitDSA(FD, false);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
+ !Stack->isLoopControlVariable(FD).first)
+ ImplicitFirstprivate.push_back(E);
+ return;
+ }
+ if (isOpenMPTargetExecutionDirective(DKind)) {
+ OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
+ if (!CheckMapClauseExpressionBase(SemaRef, E, CurComponents, OMPC_map,
+ /*NoDiagnose=*/true))
+ return;
+ auto *VD = cast<ValueDecl>(
+ CurComponents.back().getAssociatedDeclaration()->getCanonicalDecl());
+ if (!Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [&CurComponents](
+ OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents,
+ OpenMPClauseKind) {
+ auto CCI = CurComponents.rbegin();
+ auto CCE = CurComponents.rend();
+ for (const auto &SC : llvm::reverse(StackComponents)) {
+ // Do both expressions have the same kind?
+ if (CCI->getAssociatedExpression()->getStmtClass() !=
+ SC.getAssociatedExpression()->getStmtClass())
+ if (!(isa<OMPArraySectionExpr>(
+ SC.getAssociatedExpression()) &&
+ isa<ArraySubscriptExpr>(
+ CCI->getAssociatedExpression())))
+ return false;
+
+ Decl *CCD = CCI->getAssociatedDeclaration();
+ Decl *SCD = SC.getAssociatedDeclaration();
+ CCD = CCD ? CCD->getCanonicalDecl() : nullptr;
+ SCD = SCD ? SCD->getCanonicalDecl() : nullptr;
+ if (SCD != CCD)
+ return false;
+ std::advance(CCI, 1);
+ if (CCI == CCE)
+ break;
+ }
+ return true;
+ })) {
+ Visit(E->getBase());
}
} else
Visit(E->getBase());
@@ -1668,12 +2055,16 @@ public:
void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
for (auto *C : S->clauses()) {
// Skip analysis of arguments of implicitly defined firstprivate clause
- // for task directives.
- if (C && (!isa<OMPFirstprivateClause>(C) || C->getLocStart().isValid()))
+ // for task|target directives.
+ // Skip analysis of arguments of implicitly defined map clause for target
+ // directives.
+ if (C && !((isa<OMPFirstprivateClause>(C) || isa<OMPMapClause>(C)) &&
+ C->isImplicit())) {
for (auto *CC : C->children()) {
if (CC)
Visit(CC);
}
+ }
}
}
void VisitStmt(Stmt *S) {
@@ -1684,7 +2075,10 @@ public:
}
bool isErrorFound() { return ErrorFound; }
- ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
+ ArrayRef<Expr *> getImplicitFirstprivate() const {
+ return ImplicitFirstprivate;
+ }
+ ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; }
llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() {
return VarsWithInheritedDSA;
}
@@ -1700,7 +2094,9 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
- case OMPD_teams: {
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
@@ -1714,7 +2110,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
case OMPD_target_teams:
- case OMPD_target_parallel: {
+ case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd: {
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
@@ -1745,12 +2145,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_critical:
case OMPD_taskgroup:
case OMPD_distribute:
+ case OMPD_distribute_simd:
case OMPD_ordered:
case OMPD_atomic:
case OMPD_target_data:
case OMPD_target:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
case OMPD_target_simd: {
Sema::CapturedParamNameType Params[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
@@ -1821,16 +2220,9 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
case OMPD_distribute_parallel_for_simd:
- case OMPD_distribute_simd:
case OMPD_distribute_parallel_for:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_target_teams_distribute_simd: {
+ case OMPD_target_teams_distribute_parallel_for_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
@@ -1845,6 +2237,60 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy =
+ Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+
+ Sema::CapturedParamNameType ParamsTeams[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'target' with no implicit parameters.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsTeams);
+
+ Sema::CapturedParamNameType ParamsParallel[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(".previous.lb.", Context.getSizeType()),
+ std::make_pair(".previous.ub.", Context.getSizeType()),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'teams' or 'parallel'. Both regions have
+ // the same implicit parameters.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsParallel);
+ break;
+ }
+ case OMPD_target_update:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()};
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = true;
+ QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32Ty),
+ std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)),
+ std::make_pair(".privates.", Context.VoidPtrTy.withConst()),
+ std::make_pair(".copy_fn.",
+ Context.getPointerType(CopyFnType).withConst()),
+ std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ // Mark this captured region as inlined, because we don't use outlined
+ // function directly.
+ getCurCapturedRegion()->TheCapturedDecl->addAttr(
+ AlwaysInlineAttr::CreateImplicit(
+ Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange()));
+ break;
+ }
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
@@ -1852,13 +2298,10 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
- case OMPD_target_enter_data:
- case OMPD_target_exit_data:
case OMPD_declare_reduction:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
- case OMPD_target_update:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -1969,12 +2412,23 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
return StmtError();
}
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective());
OMPOrderedClause *OC = nullptr;
OMPScheduleClause *SC = nullptr;
SmallVector<OMPLinearClause *, 4> LCs;
SmallVector<OMPClauseWithPreInit *, 8> PICs;
// This is required for proper codegen.
for (auto *Clause : Clauses) {
+ if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
+ Clause->getClauseKind() == OMPC_in_reduction) {
+ // Capture taskgroup task_reduction descriptors inside the tasking regions
+ // with the corresponding in_reduction items.
+ auto *IRC = cast<OMPInReductionClause>(Clause);
+ for (auto *E : IRC->taskgroup_descriptors())
+ if (E)
+ MarkDeclarationsReferencedInExpr(E);
+ }
if (isOpenMPPrivate(Clause->getClauseKind()) ||
Clause->getClauseKind() == OMPC_copyprivate ||
(getLangOpts().OpenMPUseTLS &&
@@ -1988,7 +2442,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
}
DSAStack->setForceVarCapturing(/*V=*/false);
- } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
+ } else if (CaptureRegions.size() > 1 ||
+ CaptureRegions.back() != OMPD_unknown) {
if (auto *C = OMPClauseWithPreInit::get(Clause))
PICs.push_back(C);
if (auto *C = OMPClauseWithPostUpdate::get(Clause)) {
@@ -2036,13 +2491,11 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
return StmtError();
}
StmtResult SR = S;
- SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
- getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective());
- for (auto ThisCaptureRegion : llvm::reverse(CaptureRegions)) {
+ 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.
// TODO: add processing for other clauses.
- if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
+ if (ThisCaptureRegion != OMPD_unknown) {
for (auto *C : PICs) {
OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion();
// Find the particular capture region for the clause if the
@@ -2157,7 +2610,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
ParentRegion == OMPD_target_parallel)) ||
(CancelRegion == OMPD_for &&
(ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for ||
- ParentRegion == OMPD_target_parallel_for)) ||
+ ParentRegion == OMPD_target_parallel_for ||
+ ParentRegion == OMPD_distribute_parallel_for ||
+ ParentRegion == OMPD_teams_distribute_parallel_for ||
+ ParentRegion == OMPD_target_teams_distribute_parallel_for)) ||
(CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) ||
(CancelRegion == OMPD_sections &&
(ParentRegion == OMPD_section || ParentRegion == OMPD_sections ||
@@ -2236,7 +2692,6 @@ static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
NestingProhibited = ParentRegion != OMPD_target;
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
- Stack->setParentTeamsRegionLoc(Stack->getConstructLoc());
}
if (!NestingProhibited &&
!isOpenMPTargetExecutionDirective(CurrentRegion) &&
@@ -2390,7 +2845,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA;
bool ErrorFound = false;
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
- if (AStmt) {
+ if (AStmt && !CurContext->isDependentContext()) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
// Check default data sharing attributes for referenced variables.
@@ -2405,13 +2860,37 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
// Generate list of implicitly defined firstprivate variables.
VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA();
- if (!DSAChecker.getImplicitFirstprivate().empty()) {
+ SmallVector<Expr *, 4> ImplicitFirstprivates(
+ DSAChecker.getImplicitFirstprivate().begin(),
+ DSAChecker.getImplicitFirstprivate().end());
+ SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(),
+ DSAChecker.getImplicitMap().end());
+ // Mark taskgroup task_reduction descriptors as implicitly firstprivate.
+ for (auto *C : Clauses) {
+ if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
+ for (auto *E : IRC->taskgroup_descriptors())
+ if (E)
+ ImplicitFirstprivates.emplace_back(E);
+ }
+ }
+ if (!ImplicitFirstprivates.empty()) {
if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
- DSAChecker.getImplicitFirstprivate(), SourceLocation(),
- SourceLocation(), SourceLocation())) {
+ ImplicitFirstprivates, SourceLocation(), SourceLocation(),
+ SourceLocation())) {
ClausesWithImplicit.push_back(Implicit);
ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
- DSAChecker.getImplicitFirstprivate().size();
+ ImplicitFirstprivates.size();
+ } else
+ ErrorFound = true;
+ }
+ if (!ImplicitMaps.empty()) {
+ if (OMPClause *Implicit = ActOnOpenMPMapClause(
+ OMPC_MAP_unknown, OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true,
+ SourceLocation(), SourceLocation(), ImplicitMaps,
+ SourceLocation(), SourceLocation(), SourceLocation())) {
+ ClausesWithImplicit.emplace_back(Implicit);
+ ErrorFound |=
+ cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
} else
ErrorFound = true;
}
@@ -2558,12 +3037,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
break;
case OMPD_target_enter_data:
Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc,
- EndLoc);
+ EndLoc, AStmt);
AllowedNameModifiers.push_back(OMPD_target_enter_data);
break;
case OMPD_target_exit_data:
Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc,
- EndLoc);
+ EndLoc, AStmt);
AllowedNameModifiers.push_back(OMPD_target_exit_data);
break;
case OMPD_taskloop:
@@ -2581,9 +3060,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc, VarsWithInheritedDSA);
break;
case OMPD_target_update:
- assert(!AStmt && "Statement is not allowed for target update");
- Res =
- ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ Res = ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc,
+ EndLoc, AStmt);
AllowedNameModifiers.push_back(OMPD_target_update);
break;
case OMPD_distribute_parallel_for:
@@ -3053,21 +3531,6 @@ bool OpenMPIterationSpaceChecker::Dependent() const {
(Step && Step->isValueDependent());
}
-static Expr *getExprAsWritten(Expr *E) {
- if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E))
- E = ExprTemp->getSubExpr();
-
- if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- E = MTE->GetTemporaryExpr();
-
- while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
- E = Binder->getSubExpr();
-
- if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
- E = ICE->getSubExprAsWritten();
- return E->IgnoreParens();
-}
-
bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl,
Expr *NewLCRefExpr,
Expr *NewLB) {
@@ -3249,12 +3712,8 @@ static const ValueDecl *GetInitLCDecl(Expr *E) {
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
E = CE->getArg(0)->IgnoreParenImpCasts();
if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) {
- if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
- if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
- return getCanonicalDecl(ME->getMemberDecl());
+ if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
return getCanonicalDecl(VD);
- }
}
if (auto *ME = dyn_cast_or_null<MemberExpr>(E))
if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
@@ -3939,7 +4398,7 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) {
/// Build preinits statement for the given declarations.
static Stmt *buildPreInits(ASTContext &Context,
- SmallVectorImpl<Decl *> &PreInits) {
+ MutableArrayRef<Decl *> PreInits) {
if (!PreInits.empty()) {
return new (Context) DeclStmt(
DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()),
@@ -3949,8 +4408,9 @@ static Stmt *buildPreInits(ASTContext &Context,
}
/// Build preinits statement for the given declarations.
-static Stmt *buildPreInits(ASTContext &Context,
- llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
+static Stmt *
+buildPreInits(ASTContext &Context,
+ const llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
if (!Captures.empty()) {
SmallVector<Decl *, 16> PreInits;
for (auto &Pair : Captures)
@@ -5080,7 +5540,8 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
getCurFunction()->setHasBranchProtectedScope();
return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses,
- AStmt);
+ AStmt,
+ DSAStack->getTaskgroupReductionRef());
}
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
@@ -5924,13 +6385,23 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+ getOrderedNumberExpr(Clauses), CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -5995,7 +6466,28 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
StmtResult
Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc, Stmt *AStmt) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_enter_data);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
// OpenMP [2.10.2, Restrictions, p. 99]
// At least one map clause must appear on the directive.
if (!hasClauses(Clauses, OMPC_map)) {
@@ -6004,14 +6496,35 @@ Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses,
return StmtError();
}
- return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc,
- Clauses);
+ return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
}
StmtResult
Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc, Stmt *AStmt) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_exit_data);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
// OpenMP [2.10.3, Restrictions, p. 102]
// At least one map clause must appear on the directive.
if (!hasClauses(Clauses, OMPC_map)) {
@@ -6020,17 +6533,41 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
return StmtError();
}
- return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses);
+ return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
}
StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc,
+ Stmt *AStmt) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_update);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
if (!hasClauses(Clauses, OMPC_to, OMPC_from)) {
Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required);
return StmtError();
}
- return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses);
+ return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
}
StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
@@ -6049,6 +6586,8 @@ StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
getCurFunction()->setHasBranchProtectedScope();
+ DSAStack->setParentTeamsRegionLoc(StartLoc);
+
return OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
@@ -6215,6 +6754,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
// clause must not be specified.
if (checkReductionClauseWithNogroup(*this, Clauses))
return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
getCurFunction()->setHasBranchProtectedScope();
return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc,
@@ -6261,13 +6802,24 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_distribute_parallel_for);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_distribute_parallel_for, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6277,7 +6829,8 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
getCurFunction()->setHasBranchProtectedScope();
return OMPDistributeParallelForDirective::Create(
- Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
@@ -6294,13 +6847,24 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_distribute_parallel_for_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6308,6 +6872,17 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
@@ -6330,20 +6905,41 @@ StmtResult Sema::ActOnOpenMPDistributeSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_distribute_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt,
- *this, *DSAStack, VarsWithImplicitDSA, B);
+ nullptr /*ordered not a clause on distribute*/, CS, *this,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
@@ -6366,13 +6962,23 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+ getOrderedNumberExpr(Clauses), CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6412,13 +7018,23 @@ StmtResult Sema::ActOnOpenMPTargetSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will define the
// nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+ getOrderedNumberExpr(Clauses), CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6459,14 +7075,24 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_teams_distribute);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
CheckOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt,
- *this, *DSAStack, VarsWithImplicitDSA, B);
+ nullptr /*ordered not a clause on distribute*/, CS, *this,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6474,6 +7100,9 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective(
"omp teams distribute loop exprs were not built");
getCurFunction()->setHasBranchProtectedScope();
+
+ DSAStack->setParentTeamsRegionLoc(StartLoc);
+
return OMPTeamsDistributeDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
@@ -6492,13 +7121,25 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_teams_distribute_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
@@ -6522,6 +7163,9 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective(
return StmtError();
getCurFunction()->setHasBranchProtectedScope();
+
+ DSAStack->setParentTeamsRegionLoc(StartLoc);
+
return OMPTeamsDistributeSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
@@ -6541,12 +7185,24 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective(
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
auto NestedLoopCount = CheckOpenMPLoop(
OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
@@ -6570,6 +7226,9 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective(
return StmtError();
getCurFunction()->setHasBranchProtectedScope();
+
+ DSAStack->setParentTeamsRegionLoc(StartLoc);
+
return OMPTeamsDistributeParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
@@ -6589,12 +7248,24 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective(
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = CheckOpenMPLoop(
OMPD_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
@@ -6603,20 +7274,13 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective(
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
- if (!CurContext->isDependentContext()) {
- // Finalize the clauses that need pre-built expressions for CodeGen.
- for (auto C : Clauses) {
- if (auto *LC = dyn_cast<OMPLinearClause>(C))
- if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope,
- DSAStack))
- return StmtError();
- }
- }
-
getCurFunction()->setHasBranchProtectedScope();
+
+ DSAStack->setParentTeamsRegionLoc(StartLoc);
+
return OMPTeamsDistributeParallelForDirective::Create(
- Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses,
@@ -6634,6 +7298,16 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses,
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_teams);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
getCurFunction()->setHasBranchProtectedScope();
return OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses,
@@ -6654,14 +7328,24 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_target_teams_distribute);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
auto NestedLoopCount = CheckOpenMPLoop(
- OMPD_target_teams_distribute,
- getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ OMPD_target_teams_distribute, getCollapseNumberExpr(Clauses),
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6703,20 +7387,10 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target teams distribute parallel for loop exprs were not built");
- if (!CurContext->isDependentContext()) {
- // Finalize the clauses that need pre-built expressions for CodeGen.
- for (auto C : Clauses) {
- if (auto *LC = dyn_cast<OMPLinearClause>(C))
- if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope,
- DSAStack))
- return StmtError();
- }
- }
-
getCurFunction()->setHasBranchProtectedScope();
return OMPTargetTeamsDistributeParallelForDirective::Create(
- Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
@@ -6760,6 +7434,9 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
}
}
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
getCurFunction()->setHasBranchProtectedScope();
return OMPTargetTeamsDistributeParallelForSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
@@ -6779,13 +7456,24 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_target_teams_distribute_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
auto NestedLoopCount = CheckOpenMPLoop(
OMPD_target_teams_distribute_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -6793,6 +7481,20 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective(
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp target teams distribute simd loop exprs were not built");
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
getCurFunction()->setHasBranchProtectedScope();
return OMPTargetTeamsDistributeSimdDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
@@ -6853,6 +7555,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -6894,16 +7597,23 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
OpenMPDirectiveKind NameModifier = OMPD_unknown) {
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
-
switch (CKind) {
case OMPC_if:
switch (DKind) {
case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
// If this clause applies to the nested 'parallel' region, capture within
// the 'target' region, otherwise do not capture.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_target;
break;
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_teams;
+ break;
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -6911,15 +7621,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for_simd:
case OMPD_target:
case OMPD_target_simd:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
@@ -6965,24 +7669,84 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_num_threads:
switch (DKind) {
case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_target;
break;
- case OMPD_cancel:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_teams;
+ break;
case OMPD_parallel:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ // Do not capture num_threads-clause expressions.
+ break;
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
case OMPD_target:
case OMPD_target_simd:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_cancel:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_teams:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_num_teams:
+ switch (DKind) {
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_target;
+ break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ // Do not capture num_teams-clause expressions.
+ break;
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_task:
@@ -6992,8 +7756,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
- // Do not capture num_threads-clause expressions.
- break;
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
@@ -7004,7 +7776,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
- case OMPD_teams:
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
@@ -7018,18 +7789,36 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
+ llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
- case OMPC_num_teams:
+ case OMPC_thread_limit:
switch (DKind) {
case OMPD_target_teams:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
CaptureRegion = OMPD_target;
break;
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ // Do not capture thread_limit-clause expressions.
+ break;
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -7040,14 +7829,56 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
- case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_schedule:
+ switch (DKind) {
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_target;
+ break;
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_teams;
+ break;
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_for:
+ case OMPD_for_simd:
+ // Do not capture schedule-clause expressions.
+ break;
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
@@ -7058,8 +7889,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
- // Do not capture num_teams-clause expressions.
- break;
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel:
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
@@ -7071,8 +7908,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
- case OMPD_for:
- case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
@@ -7083,46 +7918,112 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
- llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
+ case OMPD_target_teams:
+ llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
- case OMPC_thread_limit:
+ case OMPC_dist_schedule:
switch (DKind) {
- case OMPD_target_teams:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ CaptureRegion = OMPD_teams;
+ break;
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
CaptureRegion = OMPD_target;
break;
- case OMPD_cancel:
- case OMPD_parallel:
- case OMPD_parallel_sections:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_distribute:
+ case OMPD_distribute_simd:
+ // Do not capture thread_limit-clause expressions.
+ break;
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
+ case OMPD_teams:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_target_teams:
+ llvm_unreachable("Unexpected OpenMP directive with schedule clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_device:
+ switch (DKind) {
+ case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_task:
- case OMPD_taskloop:
- case OMPD_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ // Do not capture device-clause expressions.
+ break;
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
- // Do not capture thread_limit-clause expressions.
- break;
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
case OMPD_threadprivate:
case OMPD_taskyield:
case OMPD_barrier:
@@ -7146,17 +8047,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_ordered:
case OMPD_atomic:
case OMPD_distribute_simd:
- llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
+ llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
break;
- case OMPC_schedule:
- case OMPC_dist_schedule:
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_default:
case OMPC_proc_bind:
@@ -7181,7 +8081,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_depend:
- case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
@@ -7223,7 +8122,7 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier);
- if (CaptureRegion != OMPD_unknown) {
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
llvm::MapVector<Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
@@ -7329,7 +8228,6 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
SourceLocation EndLoc) {
Expr *ValExpr = NumThreads;
Stmt *HelperValStmt = nullptr;
- OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.5, Restrictions]
// The num_threads expression must evaluate to a positive integer value.
@@ -7338,8 +8236,9 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads);
- if (CaptureRegion != OMPD_unknown) {
+ OpenMPDirectiveKind CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
llvm::MapVector<Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
@@ -7473,6 +8372,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7631,6 +8531,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7761,7 +8662,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
<< "schedule" << 1 << ChunkSize->getSourceRange();
return nullptr;
}
- } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) &&
+ } else if (getOpenMPCaptureRegionForClause(
+ DSAStack->getCurrentDirective(), OMPC_schedule) !=
+ OMPD_unknown &&
!CurContext->isDependentContext()) {
llvm::MapVector<Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
@@ -7829,6 +8732,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_shared:
case OMPC_reduction:
case OMPC_task_reduction:
+ case OMPC_in_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7946,6 +8850,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
EndLoc, ReductionIdScopeSpec,
ReductionId);
break;
+ case OMPC_in_reduction:
+ Res =
+ ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec, ReductionId);
+ break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
LinKind, DepLinMapLoc, ColonLoc, EndLoc);
@@ -8097,7 +9006,8 @@ getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
}
return std::make_pair(nullptr, false);
}
- return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false);
+ return std::make_pair(
+ getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
}
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
@@ -8299,13 +9209,19 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (!IsImplicitClause) {
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
TopDVar = DVar;
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
bool IsConstant = ElemType.isConstant(Context);
// OpenMP [2.4.13, Data-sharing Attribute Clauses]
// A list item that specifies a given variable may not appear in more
// than one clause on the same directive, except that a variable may be
// specified in both firstprivate and lastprivate clauses.
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
- DVar.CKind != OMPC_lastprivate && DVar.RefExpr) {
+ (isOpenMPDistributeDirective(CurrDir) ||
+ DVar.CKind != OMPC_lastprivate) &&
+ DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
@@ -8333,18 +9249,29 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
continue;
}
- OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.9.3.4, Restrictions, p.2]
// A list item that is private within a parallel region must not appear
// in a firstprivate clause on a worksharing construct if any of the
// worksharing regions arising from the worksharing construct ever bind
// to any of the parallel regions arising from the parallel construct.
- if (isOpenMPWorksharingDirective(CurrDir) &&
+ // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
+ // A list item that is private within a teams region must not appear in a
+ // firstprivate clause on a distribute construct if any of the distribute
+ // regions arising from the distribute construct ever bind to any of the
+ // teams regions arising from the teams construct.
+ // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
+ // A list item that appears in a reduction clause of a teams construct
+ // must not appear in a firstprivate clause on a distribute construct if
+ // any of the distribute regions arising from the distribute construct
+ // ever bind to any of the teams regions arising from the teams construct.
+ if ((isOpenMPWorksharingDirective(CurrDir) ||
+ isOpenMPDistributeDirective(CurrDir)) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared &&
(isOpenMPParallelDirective(DVar.DKind) ||
+ isOpenMPTeamsDirective(DVar.DKind) ||
DVar.DKind == OMPD_unknown)) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_firstprivate)
@@ -8369,12 +9296,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
[](OpenMPDirectiveKind K) -> bool {
return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K);
+ isOpenMPWorksharingDirective(K) ||
+ isOpenMPTeamsDirective(K);
},
- false);
+ /*FromParent=*/true);
if (DVar.CKind == OMPC_reduction &&
(isOpenMPParallelDirective(DVar.DKind) ||
- isOpenMPWorksharingDirective(DVar.DKind))) {
+ isOpenMPWorksharingDirective(DVar.DKind) ||
+ isOpenMPTeamsDirective(DVar.DKind))) {
Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate)
<< getOpenMPDirectiveName(DVar.DKind);
ReportOriginalDSA(*this, DSAStack, D, DVar);
@@ -8382,61 +9311,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
}
}
- // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
- // A list item that is private within a teams region must not appear in a
- // firstprivate clause on a distribute construct if any of the distribute
- // regions arising from the distribute construct ever bind to any of the
- // teams regions arising from the teams construct.
- // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
- // A list item that appears in a reduction clause of a teams construct
- // must not appear in a firstprivate clause on a distribute construct if
- // any of the distribute regions arising from the distribute construct
- // ever bind to any of the teams regions arising from the teams construct.
- // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
- // A list item may appear in a firstprivate or lastprivate clause but not
- // both.
- if (CurrDir == OMPD_distribute) {
- DVar = DSAStack->hasInnermostDSA(
- D, [](OpenMPClauseKind C) -> bool { return C == OMPC_private; },
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPTeamsDirective(K);
- },
- false);
- if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) {
- Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- DVar = DSAStack->hasInnermostDSA(
- D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPTeamsDirective(K);
- },
- false);
- if (DVar.CKind == OMPC_reduction &&
- isOpenMPTeamsDirective(DVar.DKind)) {
- Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- DVar = DSAStack->getTopDSA(D, false);
- if (DVar.CKind == OMPC_lastprivate) {
- Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- }
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (CurrDir == OMPD_target || CurrDir == OMPD_target_parallel ||
- CurrDir == OMPD_target_teams ||
- CurrDir == OMPD_target_teams_distribute ||
- CurrDir == OMPD_target_teams_distribute_parallel_for ||
- CurrDir == OMPD_target_teams_distribute_parallel_for_simd ||
- CurrDir == OMPD_target_teams_distribute_simd ||
- CurrDir == OMPD_target_parallel_for_simd ||
- CurrDir == OMPD_target_parallel_for) {
+ if (isOpenMPTargetExecutionDirective(CurrDir)) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -8585,14 +9463,19 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
continue;
Type = Type.getNonReferenceType();
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below.
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
- DVar.CKind != OMPC_firstprivate &&
+ (isOpenMPDistributeDirective(CurrDir) ||
+ DVar.CKind != OMPC_firstprivate) &&
(DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
@@ -8601,7 +9484,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
continue;
}
- OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.3.5, Restrictions, p.2]
// A list item that is private within a parallel region, or that appears in
// the reduction clause of a parallel construct, must not appear in a
@@ -8622,18 +9504,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
}
}
- // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
- // A list item may appear in a firstprivate or lastprivate clause but not
- // both.
- if (CurrDir == OMPD_distribute) {
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
- if (DVar.CKind == OMPC_firstprivate) {
- Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
- continue;
- }
- }
-
// OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
// A variable of class type (or array thereof) that appears in a
// lastprivate clause requires an accessible, unambiguous default
@@ -8770,7 +9640,7 @@ public:
return true;
DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(
VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; },
- false);
+ /*FromParent=*/true);
if (DVarPrivate.CKind != OMPC_unknown)
return true;
return false;
@@ -8928,6 +9798,9 @@ struct ReductionData {
SmallVector<Expr *, 8> RHSs;
/// Reduction operation expression.
SmallVector<Expr *, 8> ReductionOps;
+ /// Taskgroup descriptors for the corresponding reduction items in
+ /// in_reduction clauses.
+ SmallVector<Expr *, 8> TaskgroupDescriptors;
/// List of captures for clause.
SmallVector<Decl *, 4> ExprCaptures;
/// List of postupdate expressions.
@@ -8940,6 +9813,7 @@ struct ReductionData {
LHSs.reserve(Size);
RHSs.reserve(Size);
ReductionOps.reserve(Size);
+ TaskgroupDescriptors.reserve(Size);
ExprCaptures.reserve(Size);
ExprPostUpdates.reserve(Size);
}
@@ -8951,19 +9825,83 @@ struct ReductionData {
LHSs.emplace_back(nullptr);
RHSs.emplace_back(nullptr);
ReductionOps.emplace_back(ReductionOp);
+ TaskgroupDescriptors.emplace_back(nullptr);
}
/// Stores reduction data.
- void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS,
- Expr *ReductionOp) {
+ void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp,
+ Expr *TaskgroupDescriptor) {
Vars.emplace_back(Item);
Privates.emplace_back(Private);
LHSs.emplace_back(LHS);
RHSs.emplace_back(RHS);
ReductionOps.emplace_back(ReductionOp);
+ TaskgroupDescriptors.emplace_back(TaskgroupDescriptor);
}
};
} // namespace
+static bool CheckOMPArraySectionConstantForReduction(
+ ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement,
+ SmallVectorImpl<llvm::APSInt> &ArraySizes) {
+ const Expr *Length = OASE->getLength();
+ if (Length == nullptr) {
+ // For array sections of the form [1:] or [:], we would need to analyze
+ // the lower bound...
+ if (OASE->getColonLoc().isValid())
+ return false;
+
+ // This is an array subscript which has implicit length 1!
+ SingleElement = true;
+ ArraySizes.push_back(llvm::APSInt::get(1));
+ } else {
+ llvm::APSInt ConstantLengthValue;
+ if (!Length->EvaluateAsInt(ConstantLengthValue, Context))
+ return false;
+
+ SingleElement = (ConstantLengthValue.getSExtValue() == 1);
+ ArraySizes.push_back(ConstantLengthValue);
+ }
+
+ // Get the base of this array section and walk up from there.
+ const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
+
+ // We require length = 1 for all array sections except the right-most to
+ // guarantee that the memory region is contiguous and has no holes in it.
+ while (const auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) {
+ Length = TempOASE->getLength();
+ if (Length == nullptr) {
+ // For array sections of the form [1:] or [:], we would need to analyze
+ // the lower bound...
+ if (OASE->getColonLoc().isValid())
+ return false;
+
+ // This is an array subscript which has implicit length 1!
+ ArraySizes.push_back(llvm::APSInt::get(1));
+ } else {
+ llvm::APSInt ConstantLengthValue;
+ if (!Length->EvaluateAsInt(ConstantLengthValue, Context) ||
+ ConstantLengthValue.getSExtValue() != 1)
+ return false;
+
+ ArraySizes.push_back(ConstantLengthValue);
+ }
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ }
+
+ // If we have a single element, we don't need to add the implicit lengths.
+ if (!SingleElement) {
+ while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) {
+ // Has implicit length 1!
+ ArraySizes.push_back(llvm::APSInt::get(1));
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ }
+ }
+
+ // This array section can be privatized as a single value or as a constant
+ // sized array.
+ return true;
+}
+
static bool ActOnOMPReductionKindClause(
Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind,
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
@@ -8982,7 +9920,6 @@ static bool ActOnOMPReductionKindClause(
// C++
// reduction-identifier is either an id-expression or one of the following
// operators: +, -, *, &, |, ^, && and ||
- // FIXME: Only 'min' and 'max' identifiers are supported for now.
switch (OOK) {
case OO_Plus:
case OO_Minus:
@@ -9033,6 +9970,7 @@ static bool ActOnOMPReductionKindClause(
case OO_GreaterGreaterEqual:
case OO_EqualEqual:
case OO_ExclaimEqual:
+ case OO_Spaceship:
case OO_PlusPlus:
case OO_MinusMinus:
case OO_Comma:
@@ -9045,7 +9983,7 @@ static bool ActOnOMPReductionKindClause(
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Unexpected reduction identifier");
case OO_None:
- if (auto II = DN.getAsIdentifierInfo()) {
+ if (auto *II = DN.getAsIdentifierInfo()) {
if (II->isStr("max"))
BOK = BO_GT;
else if (II->isStr("min"))
@@ -9056,6 +9994,8 @@ static bool ActOnOMPReductionKindClause(
SourceRange ReductionIdRange;
if (ReductionIdScopeSpec.isValid())
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
+ else
+ ReductionIdRange.setBegin(ReductionId.getBeginLoc());
ReductionIdRange.setEnd(ReductionId.getEndLoc());
auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
@@ -9097,6 +10037,7 @@ static bool ActOnOMPReductionKindClause(
if (!D)
continue;
+ Expr *TaskgroupDescriptor = nullptr;
QualType Type;
auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens());
auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens());
@@ -9167,6 +10108,7 @@ static bool ActOnOMPReductionKindClause(
<< getOpenMPClauseName(ClauseKind);
if (DVar.RefExpr)
S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
+ continue;
} else if (DVar.CKind != OMPC_unknown) {
S.Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
@@ -9259,9 +10201,34 @@ static bool ActOnOMPReductionKindClause(
auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr);
auto PrivateTy = Type;
- if (OASE ||
- (!ASE &&
+
+ // Try if we can determine constant lengths for all array sections and avoid
+ // the VLA.
+ bool ConstantLengthOASE = false;
+ if (OASE) {
+ bool SingleElement;
+ llvm::SmallVector<llvm::APSInt, 4> ArraySizes;
+ ConstantLengthOASE = CheckOMPArraySectionConstantForReduction(
+ Context, OASE, SingleElement, ArraySizes);
+
+ // If we don't have a single element, we must emit a constant array type.
+ if (ConstantLengthOASE && !SingleElement) {
+ for (auto &Size : ArraySizes) {
+ PrivateTy = Context.getConstantArrayType(
+ PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ }
+ }
+ }
+
+ 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);
+ continue;
+ }
// For arrays/array sections only:
// Create pseudo array type for private copy. The size for this array will
// be generated during codegen.
@@ -9269,8 +10236,7 @@ static bool ActOnOMPReductionKindClause(
// (type of the variable or single array element).
PrivateTy = Context.getVariableArrayType(
Type,
- new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(),
- VK_RValue),
+ new (Context) OpaqueValueExpr(ELoc, Context.getSizeType(), VK_RValue),
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
} else if (!ASE && !OASE &&
Context.getAsArrayType(D->getType().getNonReferenceType()))
@@ -9352,8 +10318,7 @@ static bool ActOnOMPReductionKindClause(
if (Type->isPointerType()) {
// Cast to pointer type.
auto CastExpr = S.BuildCStyleCastExpr(
- SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
- SourceLocation(), Init);
+ ELoc, Context.getTrivialTypeSourceInfo(Type, ELoc), ELoc, Init);
if (CastExpr.isInvalid())
continue;
Init = CastExpr.get();
@@ -9378,6 +10343,7 @@ static bool ActOnOMPReductionKindClause(
case BO_GE:
case BO_EQ:
case BO_NE:
+ case BO_Cmp:
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
@@ -9447,19 +10413,72 @@ static bool ActOnOMPReductionKindClause(
S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(),
BO_Assign, LHSDRE, ReductionOp.get());
} else {
- auto *ConditionalOp = new (Context) ConditionalOperator(
- ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
- RHSDRE, Type, VK_LValue, OK_Ordinary);
+ auto *ConditionalOp = new (Context)
+ ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc, RHSDRE,
+ Type, VK_LValue, OK_Ordinary);
ReductionOp =
S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(),
BO_Assign, LHSDRE, ConditionalOp);
}
- ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get());
+ if (ReductionOp.isUsable())
+ ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get());
}
- if (ReductionOp.isInvalid())
+ if (!ReductionOp.isUsable())
continue;
}
+ // OpenMP [2.15.4.6, Restrictions, p.2]
+ // A list item that appears in an in_reduction clause of a task construct
+ // must appear in a task_reduction clause of a construct associated with a
+ // taskgroup region that includes the participating task in its taskgroup
+ // set. The construct associated with the innermost region that meets this
+ // condition must specify the same reduction-identifier as the in_reduction
+ // clause.
+ if (ClauseKind == OMPC_in_reduction) {
+ SourceRange ParentSR;
+ BinaryOperatorKind ParentBOK;
+ const Expr *ParentReductionOp;
+ Expr *ParentBOKTD, *ParentReductionOpTD;
+ DSAStackTy::DSAVarData ParentBOKDSA =
+ Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK,
+ ParentBOKTD);
+ DSAStackTy::DSAVarData ParentReductionOpDSA =
+ Stack->getTopMostTaskgroupReductionData(
+ D, ParentSR, ParentReductionOp, ParentReductionOpTD);
+ bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown;
+ bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown;
+ if (!IsParentBOK && !IsParentReductionOp) {
+ S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction);
+ continue;
+ }
+ if ((DeclareReductionRef.isUnset() && IsParentReductionOp) ||
+ (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK ||
+ IsParentReductionOp) {
+ bool EmitError = true;
+ if (IsParentReductionOp && DeclareReductionRef.isUsable()) {
+ llvm::FoldingSetNodeID RedId, ParentRedId;
+ ParentReductionOp->Profile(ParentRedId, Context, /*Canonical=*/true);
+ DeclareReductionRef.get()->Profile(RedId, Context,
+ /*Canonical=*/true);
+ EmitError = RedId != ParentRedId;
+ }
+ if (EmitError) {
+ S.Diag(ReductionId.getLocStart(),
+ diag::err_omp_reduction_identifier_mismatch)
+ << ReductionIdRange << RefExpr->getSourceRange();
+ S.Diag(ParentSR.getBegin(),
+ diag::note_omp_previous_reduction_identifier)
+ << ParentSR
+ << (IsParentBOK ? ParentBOKDSA.RefExpr
+ : ParentReductionOpDSA.RefExpr)
+ ->getSourceRange();
+ continue;
+ }
+ }
+ TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD;
+ assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined.");
+ }
+
DeclRefExpr *Ref = nullptr;
Expr *VarsExpr = RefExpr->IgnoreParens();
if (!VD && !S.CurContext->isDependentContext()) {
@@ -9497,7 +10516,15 @@ static bool ActOnOMPReductionKindClause(
// All reduction items are still marked as reduction (to do not increase
// code base size).
Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
- RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get());
+ if (CurrDir == OMPD_taskgroup) {
+ if (DeclareReductionRef.isUsable())
+ Stack->addTaskgroupReductionData(D, ReductionIdRange,
+ DeclareReductionRef.get());
+ else
+ Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK);
+ }
+ RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(),
+ TaskgroupDescriptor);
}
return RD.Vars.empty();
}
@@ -9544,6 +10571,27 @@ OMPClause *Sema::ActOnOpenMPTaskReductionClause(
buildPostUpdate(*this, RD.ExprPostUpdates));
}
+OMPClause *Sema::ActOnOpenMPInReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ ReductionData RD(VarList.size());
+
+ if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_in_reduction, VarList,
+ StartLoc, LParenLoc, ColonLoc, EndLoc,
+ ReductionIdScopeSpec, ReductionId,
+ UnresolvedReductions, RD))
+ return nullptr;
+
+ return OMPInReductionClause::Create(
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.TaskgroupDescriptors,
+ buildPreInits(Context, RD.ExprCaptures),
+ buildPostUpdate(*this, RD.ExprPostUpdates));
+}
+
bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
SourceLocation LinLoc) {
if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
@@ -9768,11 +10816,19 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
HasErrors = true;
continue;
}
- if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) {
- D = cast<MemberExpr>(CED->getInit()->IgnoreParenImpCasts())
- ->getMemberDecl();
- }
auto &&Info = Stack->isLoopControlVariable(D);
+ // OpenMP [2.15.11, distribute simd Construct]
+ // A list item may not appear in a linear clause, unless it is the loop
+ // iteration variable.
+ if (isOpenMPDistributeDirective(Stack->getCurrentDirective()) &&
+ isOpenMPSimdDirective(Stack->getCurrentDirective()) && !Info.first) {
+ SemaRef.Diag(ELoc,
+ diag::err_omp_linear_distribute_var_non_loop_iteration);
+ Updates.push_back(nullptr);
+ Finals.push_back(nullptr);
+ HasErrors = true;
+ continue;
+ }
Expr *InitExpr = *CurInit;
// Build privatized reference to the current linear var.
@@ -10239,23 +11295,26 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
}
OpsOffs.push_back({RHS, OOK});
} else {
- // OpenMP [2.11.1.1, Restrictions, p.3]
- // A variable that is part of another variable (such as a field of a
- // structure) but is not an array element or an array section cannot
- // appear in a depend clause.
- auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
- auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
- (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) ||
(ASE &&
!ASE->getBase()
->getType()
.getNonReferenceType()
->isPointerType() &&
!ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item)
- << 0 << RefExpr->getSourceRange();
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << RefExpr->getSourceRange();
+ continue;
+ }
+ bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
+ getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ ExprResult Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ getDiagnostics().setSuppressAllDiagnostics(Suppress);
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << RefExpr->getSourceRange();
continue;
}
}
@@ -10284,6 +11343,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Device;
+ Stmt *HelperValStmt = nullptr;
// OpenMP [2.9.1, Restrictions]
// The device expression must evaluate to a non-negative integer value.
@@ -10291,48 +11351,17 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
/*StrictlyPositive=*/false))
return nullptr;
- return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc);
-}
-
-static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc,
- DSAStackTy *Stack, CXXRecordDecl *RD) {
- if (!RD || RD->isInvalidDecl())
- return true;
-
- auto QTy = SemaRef.Context.getRecordType(RD);
- if (RD->isDynamicClass()) {
- SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
- SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target);
- return false;
- }
- auto *DC = RD;
- bool IsCorrect = true;
- for (auto *I : DC->decls()) {
- if (I) {
- if (auto *MD = dyn_cast<CXXMethodDecl>(I)) {
- if (MD->isStatic()) {
- SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
- SemaRef.Diag(MD->getLocation(),
- diag::note_omp_static_member_in_target);
- IsCorrect = false;
- }
- } else if (auto *VD = dyn_cast<VarDecl>(I)) {
- if (VD->isStaticDataMember()) {
- SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy;
- SemaRef.Diag(VD->getLocation(),
- diag::note_omp_static_member_in_target);
- IsCorrect = false;
- }
- }
- }
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ OpenMPDirectiveKind CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_device);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
}
- for (auto &I : RD->bases()) {
- if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack,
- I.getType()->getAsCXXRecordDecl()))
- IsCorrect = false;
- }
- return IsCorrect;
+ return new (Context)
+ OMPDeviceClause(ValExpr, HelperValStmt, StartLoc, LParenLoc, EndLoc);
}
static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
@@ -10341,9 +11370,6 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
if (QTy->isIncompleteType(&ND)) {
SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR;
return false;
- } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(ND)) {
- if (!RD->isInvalidDecl() && !IsCXXRecordForMappable(SemaRef, SL, Stack, RD))
- return false;
}
return true;
}
@@ -10443,7 +11469,7 @@ static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
static Expr *CheckMapClauseExpressionBase(
Sema &SemaRef, Expr *E,
OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
- OpenMPClauseKind CKind) {
+ OpenMPClauseKind CKind, bool NoDiagnose) {
SourceLocation ELoc = E->getExprLoc();
SourceRange ERange = E->getSourceRange();
@@ -10493,7 +11519,7 @@ static Expr *CheckMapClauseExpressionBase(
if (auto *CurE = dyn_cast<DeclRefExpr>(E)) {
if (!isa<VarDecl>(CurE->getDecl()))
- break;
+ return nullptr;
RelevantExpr = CurE;
@@ -10503,12 +11529,8 @@ static Expr *CheckMapClauseExpressionBase(
AllowWholeSizeArraySection = false;
// Record the component.
- CurComponents.push_back(OMPClauseMappableExprCommon::MappableComponent(
- CurE, CurE->getDecl()));
- continue;
- }
-
- if (auto *CurE = dyn_cast<MemberExpr>(E)) {
+ CurComponents.emplace_back(CurE, CurE->getDecl());
+ } else if (auto *CurE = dyn_cast<MemberExpr>(E)) {
auto *BaseE = CurE->getBase()->IgnoreParenImpCasts();
if (isa<CXXThisExpr>(BaseE))
@@ -10518,9 +11540,14 @@ static Expr *CheckMapClauseExpressionBase(
E = BaseE;
if (!isa<FieldDecl>(CurE->getMemberDecl())) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
- << CurE->getSourceRange();
- break;
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
+ << CurE->getSourceRange();
+ return nullptr;
+ }
+ if (RelevantExpr)
+ return nullptr;
+ continue;
}
auto *FD = cast<FieldDecl>(CurE->getMemberDecl());
@@ -10529,9 +11556,14 @@ static Expr *CheckMapClauseExpressionBase(
// A bit-field cannot appear in a map clause.
//
if (FD->isBitField()) {
- SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
- << CurE->getSourceRange() << getOpenMPClauseName(CKind);
- break;
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
+ << CurE->getSourceRange() << getOpenMPClauseName(CKind);
+ return nullptr;
+ }
+ if (RelevantExpr)
+ return nullptr;
+ continue;
}
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
@@ -10543,12 +11575,16 @@ static Expr *CheckMapClauseExpressionBase(
// A list item cannot be a variable that is a member of a structure with
// a union type.
//
- if (auto *RT = CurType->getAs<RecordType>())
+ if (auto *RT = CurType->getAs<RecordType>()) {
if (RT->isUnionType()) {
- SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
- << CurE->getSourceRange();
- break;
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
+ << CurE->getSourceRange();
+ return nullptr;
+ }
+ continue;
}
+ }
// If we got a member expression, we should not expect any array section
// before that:
@@ -10561,18 +11597,17 @@ static Expr *CheckMapClauseExpressionBase(
AllowWholeSizeArraySection = false;
// Record the component.
- CurComponents.push_back(
- OMPClauseMappableExprCommon::MappableComponent(CurE, FD));
- continue;
- }
-
- if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) {
+ CurComponents.emplace_back(CurE, FD);
+ } else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) {
E = CurE->getBase()->IgnoreParenImpCasts();
if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
- << 0 << CurE->getSourceRange();
- break;
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << CurE->getSourceRange();
+ return nullptr;
+ }
+ continue;
}
// If we got an array subscript that express the whole dimension we
@@ -10583,15 +11618,12 @@ static Expr *CheckMapClauseExpressionBase(
AllowWholeSizeArraySection = false;
// Record the component - we don't have any declaration associated.
- CurComponents.push_back(
- OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr));
- continue;
- }
-
- if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
+ CurComponents.emplace_back(CurE, nullptr);
+ } else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
+ assert(!NoDiagnose && "Array sections cannot be implicitly mapped.");
E = CurE->getBase()->IgnoreParenImpCasts();
- auto CurType =
+ QualType CurType =
OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
// OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
@@ -10605,7 +11637,7 @@ static Expr *CheckMapClauseExpressionBase(
if (!IsPointer && !CurType->isArrayType()) {
SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
<< 0 << CurE->getSourceRange();
- break;
+ return nullptr;
}
bool NotWhole =
@@ -10628,20 +11660,20 @@ static Expr *CheckMapClauseExpressionBase(
SemaRef.Diag(
ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
<< CurE->getSourceRange();
- break;
+ return nullptr;
}
// Record the component - we don't have any declaration associated.
- CurComponents.push_back(
- OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr));
- continue;
+ CurComponents.emplace_back(CurE, nullptr);
+ } else {
+ if (!NoDiagnose) {
+ // If nothing else worked, this is not a valid map clause expression.
+ SemaRef.Diag(
+ ELoc, diag::err_omp_expected_named_var_member_or_array_expression)
+ << ERange;
+ }
+ return nullptr;
}
-
- // If nothing else worked, this is not a valid map clause expression.
- SemaRef.Diag(ELoc,
- diag::err_omp_expected_named_var_member_or_array_expression)
- << ERange;
- break;
}
return RelevantExpr;
@@ -10932,8 +11964,8 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
// Obtain the array or member expression bases if required. Also, fill the
// components array with all the components identified in the process.
- auto *BE =
- CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, CKind);
+ auto *BE = CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents,
+ CKind, /*NoDiagnose=*/false);
if (!BE)
continue;
@@ -11123,7 +12155,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart(
Decls.reserve(ReductionTypes.size());
LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
// A reduction-identifier may not be re-declared in the current scope for the
// same type or for a type that is compatible according to the base language
@@ -11253,7 +12285,7 @@ void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) {
DRD->setInvalidDecl();
}
-void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
+VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
// Enter new function scope.
@@ -11292,10 +12324,11 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
DRD->addDecl(OmpPrivParm);
DRD->addDecl(OmpOrigParm);
}
+ return OmpPrivParm;
}
-void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D,
- Expr *Initializer) {
+void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer,
+ VarDecl *OmpPrivParm) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
@@ -11303,10 +12336,16 @@ void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D,
PopDeclContext();
PopFunctionScopeInfo();
- if (Initializer != nullptr)
- DRD->setInitializer(Initializer);
- else
+ if (Initializer != nullptr) {
+ DRD->setInitializer(Initializer, OMPDeclareReductionDecl::CallInit);
+ } else if (OmpPrivParm->hasInit()) {
+ DRD->setInitializer(OmpPrivParm->getInit(),
+ OmpPrivParm->isDirectInit()
+ ? OMPDeclareReductionDecl::DirectInit
+ : OMPDeclareReductionDecl::CopyInit);
+ } else {
DRD->setInvalidDecl();
+ }
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
@@ -11328,7 +12367,6 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
SourceLocation EndLoc) {
Expr *ValExpr = NumTeams;
Stmt *HelperValStmt = nullptr;
- OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [teams Constrcut, Restrictions]
// The num_teams expression must evaluate to a positive integer value.
@@ -11337,8 +12375,9 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams);
- if (CaptureRegion != OMPD_unknown) {
+ OpenMPDirectiveKind CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
llvm::MapVector<Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
@@ -11354,7 +12393,6 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
SourceLocation EndLoc) {
Expr *ValExpr = ThreadLimit;
Stmt *HelperValStmt = nullptr;
- OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [teams Constrcut, Restrictions]
// The thread_limit expression must evaluate to a positive integer value.
@@ -11363,8 +12401,9 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit);
- if (CaptureRegion != OMPD_unknown) {
+ OpenMPDirectiveKind CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
llvm::MapVector<Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
HelperValStmt = buildPreInits(Context, Captures);
@@ -11471,7 +12510,9 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause(
<< "dist_schedule" << ChunkSize->getSourceRange();
return nullptr;
}
- } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) &&
+ } else if (getOpenMPCaptureRegionForClause(
+ DSAStack->getCurrentDirective(), OMPC_dist_schedule) !=
+ OMPD_unknown &&
!CurContext->isDependentContext()) {
llvm::MapVector<Expr *, DeclRefExpr *> Captures;
ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
@@ -11508,6 +12549,7 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
<< Value << getOpenMPClauseName(OMPC_defaultmap);
return nullptr;
}
+ DSAStack->setDefaultDMAToFromScalar(StartLoc);
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
@@ -11517,7 +12559,11 @@ bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
DeclContext *CurLexicalContext = getCurLexicalContext();
if (!CurLexicalContext->isFileContext() &&
!CurLexicalContext->isExternCContext() &&
- !CurLexicalContext->isExternCXXContext()) {
+ !CurLexicalContext->isExternCXXContext() &&
+ !isa<CXXRecordDecl>(CurLexicalContext) &&
+ !isa<ClassTemplateDecl>(CurLexicalContext) &&
+ !isa<ClassTemplatePartialSpecializationDecl>(CurLexicalContext) &&
+ !isa<ClassTemplateSpecializationDecl>(CurLexicalContext)) {
Diag(Loc, diag::err_omp_region_not_file_context);
return false;
}
@@ -11574,7 +12620,7 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
ND->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
- checkDeclIsAllowedInOpenMPTarget(nullptr, ND);
+ checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc());
} else if (ND->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() != MT) {
Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link)
<< Id.getName();
@@ -11663,7 +12709,8 @@ static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
return true;
}
-void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) {
+void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
+ SourceLocation IdLoc) {
if (!D || D->isInvalidDecl())
return;
SourceRange SR = E ? E->getSourceRange() : D->getSourceRange();
@@ -11692,6 +12739,16 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) {
return;
}
}
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->hasAttr<OMPDeclareTargetDeclAttr>() &&
+ (FD->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() ==
+ OMPDeclareTargetDeclAttr::MT_Link)) {
+ assert(IdLoc.isValid() && "Source location is expected");
+ Diag(IdLoc, diag::err_omp_function_in_link_clause);
+ Diag(FD->getLocation(), diag::note_defined_here) << FD;
+ return;
+ }
+ }
if (!E) {
// Checking declaration inside declare target region.
if (!D->hasAttr<OMPDeclareTargetDeclAttr>() &&
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 36f24fd9c463..268be9430a56 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandidates() {
}
}
-void OverloadCandidateSet::clear() {
+void OverloadCandidateSet::clear(CandidateSetKind CSK) {
destroyCandidates();
SlabAllocator.Reset();
NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
+ Kind = CSK;
}
namespace {
@@ -1481,6 +1482,23 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
.getTypePtr());
Changed = true;
}
+
+ // Convert FromFPT's ExtParameterInfo if necessary. The conversion is valid
+ // only if the ExtParameterInfo lists of the two function prototypes can be
+ // merged and the merged list is identical to ToFPT's ExtParameterInfo list.
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos;
+ bool CanUseToFPT, CanUseFromFPT;
+ if (Context.mergeExtParameterInfo(ToFPT, FromFPT, CanUseToFPT,
+ CanUseFromFPT, NewParamInfos) &&
+ CanUseToFPT && !CanUseFromFPT) {
+ FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo();
+ ExtInfo.ExtParameterInfos =
+ NewParamInfos.empty() ? nullptr : NewParamInfos.data();
+ QualType QT = Context.getFunctionType(FromFPT->getReturnType(),
+ FromFPT->getParamTypes(), ExtInfo);
+ FromFn = QT->getAs<FunctionType>();
+ Changed = true;
+ }
}
if (!Changed)
@@ -2663,8 +2681,12 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// Argument types are too different. Abort.
return false;
}
- if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType,
- ToFunctionType))
+
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> NewParamInfos;
+ bool CanUseToFPT, CanUseFromFPT;
+ if (!Context.mergeExtParameterInfo(ToFunctionType, FromFunctionType,
+ CanUseToFPT, CanUseFromFPT,
+ NewParamInfos))
return false;
ConvertedType = ToType;
@@ -3154,6 +3176,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
for (auto *D : S.LookupConstructors(To)) {
auto Info = getConstructorInfo(D);
if (!Info)
@@ -3182,7 +3205,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
OverloadCandidateSet::iterator Best;
switch (auto Result =
CandidateSet.BestViableFunction(S, From->getLocStart(),
- Best, true)) {
+ Best)) {
case OR_Deleted:
case OR_Success: {
// Record the standard conversion we used and the conversion function.
@@ -3229,6 +3252,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool AllowExplicit,
bool AllowObjCConversionOnExplicit) {
assert(AllowExplicit || !AllowObjCConversionOnExplicit);
+ CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Whether we will only visit constructors.
bool ConstructorsOnly = false;
@@ -3264,7 +3288,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (Result != OR_No_Viable_Function)
return Result;
// Never mind.
- CandidateSet.clear();
+ CandidateSet.clear(
+ OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// If we're list-initializing, we pass the individual elements as
// arguments, not the entire list.
@@ -3354,7 +3379,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
OverloadCandidateSet::iterator Best;
switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(),
- Best, true)) {
+ Best)) {
case OR_Success:
case OR_Deleted:
// Record the standard conversion we used and the conversion function.
@@ -4288,7 +4313,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet CandidateSet(
+ DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -4358,7 +4384,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
- switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
+ switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
case OR_Success:
// C++ [over.ics.ref]p1:
//
@@ -6317,24 +6343,36 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
OverloadCandidateSet& CandidateSet,
TemplateArgumentListInfo *ExplicitTemplateArgs,
bool SuppressUserConversions,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ bool FirstArgumentIsBase) {
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ ArrayRef<Expr *> FunctionArgs = Args;
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
QualType ObjectType;
Expr::Classification ObjectClassification;
- if (Expr *E = Args[0]) {
- // Use the explit base to restrict the lookup:
- ObjectType = E->getType();
- ObjectClassification = E->Classify(Context);
- } // .. else there is an implit base.
+ if (Args.size() > 0) {
+ if (Expr *E = Args[0]) {
+ // Use the explit base to restrict the lookup:
+ ObjectType = E->getType();
+ ObjectClassification = E->Classify(Context);
+ } // .. else there is an implit base.
+ FunctionArgs = Args.slice(1);
+ }
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
- ObjectClassification, Args.slice(1), CandidateSet,
+ ObjectClassification, FunctionArgs, CandidateSet,
SuppressUserConversions, PartialOverloading);
} else {
- AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
+ // Slice the first argument (which is the base) when we access
+ // static method as non-static
+ if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) &&
+ !isa<CXXConstructorDecl>(FD)))) {
+ assert(cast<CXXMethodDecl>(FD)->isStatic());
+ FunctionArgs = Args.slice(1);
+ }
+ AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
SuppressUserConversions, PartialOverloading);
}
} else {
@@ -6767,7 +6805,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet,
- bool AllowObjCConversionOnExplicit) {
+ bool AllowObjCConversionOnExplicit,
+ bool AllowResultConversion) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -6782,6 +6821,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
ConvType = Conversion->getConversionType().getNonReferenceType();
}
+ // If we don't allow any conversion of the result type, ignore conversion
+ // functions that don't convert to exactly (possibly cv-qualified) T.
+ if (!AllowResultConversion &&
+ !Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType))
+ return;
+
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
// operator is only a candidate if its return type is the target type or
// can be converted to the target type with a qualification conversion.
@@ -6935,7 +6980,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
CXXRecordDecl *ActingDC,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet,
- bool AllowObjCConversionOnExplicit) {
+ bool AllowObjCConversionOnExplicit,
+ bool AllowResultConversion) {
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
"Only conversion function templates permitted here");
@@ -6964,7 +7010,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
// template argument deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
- CandidateSet, AllowObjCConversionOnExplicit);
+ CandidateSet, AllowObjCConversionOnExplicit,
+ AllowResultConversion);
}
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -7568,53 +7615,62 @@ class BuiltinOperatorOverloadBuilder {
SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
OverloadCandidateSet &CandidateSet;
- // Define some constants used to index and iterate over the arithemetic types
- // provided via the getArithmeticType() method below.
- // The "promoted arithmetic types" are the arithmetic
+ static constexpr int ArithmeticTypesCap = 24;
+ SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes;
+
+ // Define some indices used to iterate over the arithemetic types in
+ // ArithmeticTypes. The "promoted arithmetic types" are the arithmetic
// types are that preserved by promotion (C++ [over.built]p2).
- static const unsigned FirstIntegralType = 4;
- static const unsigned LastIntegralType = 21;
- static const unsigned FirstPromotedIntegralType = 4,
- LastPromotedIntegralType = 12;
- static const unsigned FirstPromotedArithmeticType = 0,
- LastPromotedArithmeticType = 12;
- static const unsigned NumArithmeticTypes = 21;
-
- /// \brief Get the canonical type for a given arithmetic type index.
- CanQualType getArithmeticType(unsigned index) {
- assert(index < NumArithmeticTypes);
- static CanQualType ASTContext::* const
- ArithmeticTypes[NumArithmeticTypes] = {
- // Start of promoted types.
- &ASTContext::FloatTy,
- &ASTContext::DoubleTy,
- &ASTContext::LongDoubleTy,
- &ASTContext::Float128Ty,
-
- // Start of integral types.
- &ASTContext::IntTy,
- &ASTContext::LongTy,
- &ASTContext::LongLongTy,
- &ASTContext::Int128Ty,
- &ASTContext::UnsignedIntTy,
- &ASTContext::UnsignedLongTy,
- &ASTContext::UnsignedLongLongTy,
- &ASTContext::UnsignedInt128Ty,
- // End of promoted types.
-
- &ASTContext::BoolTy,
- &ASTContext::CharTy,
- &ASTContext::WCharTy,
- &ASTContext::Char16Ty,
- &ASTContext::Char32Ty,
- &ASTContext::SignedCharTy,
- &ASTContext::ShortTy,
- &ASTContext::UnsignedCharTy,
- &ASTContext::UnsignedShortTy,
- // End of integral types.
- // FIXME: What about complex? What about half?
- };
- return S.Context.*ArithmeticTypes[index];
+ unsigned FirstIntegralType,
+ LastIntegralType;
+ unsigned FirstPromotedIntegralType,
+ LastPromotedIntegralType;
+ unsigned FirstPromotedArithmeticType,
+ LastPromotedArithmeticType;
+ unsigned NumArithmeticTypes;
+
+ void InitArithmeticTypes() {
+ // Start of promoted types.
+ FirstPromotedArithmeticType = 0;
+ ArithmeticTypes.push_back(S.Context.FloatTy);
+ ArithmeticTypes.push_back(S.Context.DoubleTy);
+ ArithmeticTypes.push_back(S.Context.LongDoubleTy);
+ if (S.Context.getTargetInfo().hasFloat128Type())
+ ArithmeticTypes.push_back(S.Context.Float128Ty);
+
+ // Start of integral types.
+ FirstIntegralType = ArithmeticTypes.size();
+ FirstPromotedIntegralType = ArithmeticTypes.size();
+ ArithmeticTypes.push_back(S.Context.IntTy);
+ ArithmeticTypes.push_back(S.Context.LongTy);
+ ArithmeticTypes.push_back(S.Context.LongLongTy);
+ if (S.Context.getTargetInfo().hasInt128Type())
+ ArithmeticTypes.push_back(S.Context.Int128Ty);
+ ArithmeticTypes.push_back(S.Context.UnsignedIntTy);
+ ArithmeticTypes.push_back(S.Context.UnsignedLongTy);
+ ArithmeticTypes.push_back(S.Context.UnsignedLongLongTy);
+ if (S.Context.getTargetInfo().hasInt128Type())
+ ArithmeticTypes.push_back(S.Context.UnsignedInt128Ty);
+ LastPromotedIntegralType = ArithmeticTypes.size();
+ LastPromotedArithmeticType = ArithmeticTypes.size();
+ // End of promoted types.
+
+ ArithmeticTypes.push_back(S.Context.BoolTy);
+ ArithmeticTypes.push_back(S.Context.CharTy);
+ ArithmeticTypes.push_back(S.Context.WCharTy);
+ ArithmeticTypes.push_back(S.Context.Char16Ty);
+ ArithmeticTypes.push_back(S.Context.Char32Ty);
+ ArithmeticTypes.push_back(S.Context.SignedCharTy);
+ ArithmeticTypes.push_back(S.Context.ShortTy);
+ ArithmeticTypes.push_back(S.Context.UnsignedCharTy);
+ ArithmeticTypes.push_back(S.Context.UnsignedShortTy);
+ LastIntegralType = ArithmeticTypes.size();
+ NumArithmeticTypes = ArithmeticTypes.size();
+ // End of integral types.
+ // FIXME: What about complex? What about half?
+
+ assert(ArithmeticTypes.size() <= ArithmeticTypesCap &&
+ "Enough inline storage for all arithmetic types.");
}
/// \brief Helper method to factor out the common pattern of adding overloads
@@ -7673,18 +7729,8 @@ public:
HasArithmeticOrEnumeralCandidateType),
CandidateTypes(CandidateTypes),
CandidateSet(CandidateSet) {
- // Validate some of our static helper constants in debug builds.
- assert(getArithmeticType(FirstPromotedIntegralType) == S.Context.IntTy &&
- "Invalid first promoted integral type");
- assert(getArithmeticType(LastPromotedIntegralType - 1)
- == S.Context.UnsignedInt128Ty &&
- "Invalid last promoted integral type");
- assert(getArithmeticType(FirstPromotedArithmeticType)
- == S.Context.FloatTy &&
- "Invalid first promoted arithmetic type");
- assert(getArithmeticType(LastPromotedArithmeticType - 1)
- == S.Context.UnsignedInt128Ty &&
- "Invalid last promoted arithmetic type");
+
+ InitArithmeticTypes();
}
// C++ [over.built]p3:
@@ -7711,7 +7757,7 @@ public:
for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
Arith < NumArithmeticTypes; ++Arith) {
addPlusPlusMinusMinusStyleOverloads(
- getArithmeticType(Arith),
+ ArithmeticTypes[Arith],
VisibleTypeConversionsQuals.hasVolatile(),
VisibleTypeConversionsQuals.hasRestrict());
}
@@ -7784,7 +7830,7 @@ public:
for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
- QualType ArithTy = getArithmeticType(Arith);
+ QualType ArithTy = ArithmeticTypes[Arith];
S.AddBuiltinCandidate(&ArithTy, Args, CandidateSet);
}
@@ -7824,7 +7870,7 @@ public:
for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
- QualType IntTy = getArithmeticType(Int);
+ QualType IntTy = ArithmeticTypes[Int];
S.AddBuiltinCandidate(&IntTy, Args, CandidateSet);
}
@@ -8052,8 +8098,8 @@ public:
Left < LastPromotedArithmeticType; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
- QualType LandR[2] = { getArithmeticType(Left),
- getArithmeticType(Right) };
+ QualType LandR[2] = { ArithmeticTypes[Left],
+ ArithmeticTypes[Right] };
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
@@ -8096,8 +8142,8 @@ public:
Left < LastPromotedIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
- QualType LandR[2] = { getArithmeticType(Left),
- getArithmeticType(Right) };
+ QualType LandR[2] = { ArithmeticTypes[Left],
+ ArithmeticTypes[Right] };
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
@@ -8277,18 +8323,18 @@ public:
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType ParamTypes[2];
- ParamTypes[1] = getArithmeticType(Right);
+ ParamTypes[1] = ArithmeticTypes[Right];
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
- S.Context.getLValueReferenceType(getArithmeticType(Left));
+ S.Context.getLValueReferenceType(ArithmeticTypes[Left]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
ParamTypes[0] =
- S.Context.getVolatileType(getArithmeticType(Left));
+ S.Context.getVolatileType(ArithmeticTypes[Left]);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
@@ -8343,15 +8389,15 @@ public:
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType ParamTypes[2];
- ParamTypes[1] = getArithmeticType(Right);
+ ParamTypes[1] = ArithmeticTypes[Right];
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
- S.Context.getLValueReferenceType(getArithmeticType(Left));
+ S.Context.getLValueReferenceType(ArithmeticTypes[Left]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
if (VisibleTypeConversionsQuals.hasVolatile()) {
// Add this built-in operator as a candidate (VQ is 'volatile').
- ParamTypes[0] = getArithmeticType(Left);
+ ParamTypes[0] = ArithmeticTypes[Left];
ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
@@ -8646,6 +8692,9 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
OpBuilder.addGenericBinaryArithmeticOverloads();
break;
+ case OO_Spaceship:
+ llvm_unreachable("<=> expressions not supported yet");
+
case OO_Percent:
case OO_Caret:
case OO_Pipe:
@@ -8823,10 +8872,9 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
-bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
- const OverloadCandidate &Cand2,
- SourceLocation Loc,
- bool UserDefinedConversion) {
+bool clang::isBetterOverloadCandidate(
+ Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2,
+ SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) {
// Define viable functions to be better candidates than non-viable
// functions.
if (!Cand2.Viable)
@@ -8908,7 +8956,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// the type of the entity being initialized) is a better
// conversion sequence than the standard conversion sequence
// from the return type of F2 to the destination type.
- if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
+ if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion &&
+ Cand1.Function && Cand2.Function &&
isa<CXXConversionDecl>(Cand1.Function) &&
isa<CXXConversionDecl>(Cand2.Function)) {
// First check whether we prefer one of the conversion functions over the
@@ -8930,11 +8979,17 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// C++14 [over.match.best]p1 section 2 bullet 3.
}
- // -- F1 is generated from a deduction-guide and F2 is not
- auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
- auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
- if (Guide1 && Guide2 && Guide1->isImplicit() != Guide2->isImplicit())
- return Guide2->isImplicit();
+ // FIXME: Work around a defect in the C++17 guaranteed copy elision wording,
+ // as combined with the resolution to CWG issue 243.
+ //
+ // When the context is initialization by constructor ([over.match.ctor] or
+ // either phase of [over.match.list]), a constructor is preferred over
+ // a conversion function.
+ if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
+ Cand1.Function && Cand2.Function &&
+ isa<CXXConstructorDecl>(Cand1.Function) !=
+ isa<CXXConstructorDecl>(Cand2.Function))
+ return isa<CXXConstructorDecl>(Cand1.Function);
// -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
@@ -8980,6 +9035,21 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// Inherited from sibling base classes: still ambiguous.
}
+ // Check C++17 tie-breakers for deduction guides.
+ {
+ auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
+ auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
+ if (Guide1 && Guide2) {
+ // -- F1 is generated from a deduction-guide and F2 is not
+ if (Guide1->isImplicit() != Guide2->isImplicit())
+ return Guide2->isImplicit();
+
+ // -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not
+ if (Guide1->isCopyDeductionCandidate())
+ return true;
+ }
+ }
+
// Check for enable_if value-based overload resolution.
if (Cand1.Function && Cand2.Function) {
Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
@@ -9079,8 +9149,7 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
/// \returns The result of overload resolution.
OverloadingResult
OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
- iterator &Best,
- bool UserDefinedConversion) {
+ iterator &Best) {
llvm::SmallVector<OverloadCandidate *, 16> Candidates;
std::transform(begin(), end(), std::back_inserter(Candidates),
[](OverloadCandidate &Cand) { return &Cand; });
@@ -9114,8 +9183,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
Best = end();
for (auto *Cand : Candidates)
if (Cand->Viable)
- if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc,
- UserDefinedConversion))
+ if (Best == end() ||
+ isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
// If we didn't find any viable functions, abort.
@@ -9127,10 +9196,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Make sure that this function is better than every other viable
// function. If not, we have an ambiguity.
for (auto *Cand : Candidates) {
- if (Cand->Viable &&
- Cand != Best &&
- !isBetterOverloadCandidate(S, *Best, *Cand, Loc,
- UserDefinedConversion)) {
+ if (Cand->Viable && Cand != Best &&
+ !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
Cand->Function)) {
EquivalentCands.push_back(Cand->Function);
@@ -10222,9 +10289,12 @@ struct CompareOverloadCandidatesForDisplay {
Sema &S;
SourceLocation Loc;
size_t NumArgs;
+ OverloadCandidateSet::CandidateSetKind CSK;
- CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs)
- : S(S), NumArgs(nArgs) {}
+ CompareOverloadCandidatesForDisplay(
+ Sema &S, SourceLocation Loc, size_t NArgs,
+ OverloadCandidateSet::CandidateSetKind CSK)
+ : S(S), NumArgs(NArgs), CSK(CSK) {}
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
@@ -10238,8 +10308,10 @@ struct CompareOverloadCandidatesForDisplay {
// TODO: introduce a tri-valued comparison for overload
// candidates. Would be more worthwhile if we had a sort
// that could exploit it.
- if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true;
- if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false;
+ if (isBetterOverloadCandidate(S, *L, *R, SourceLocation(), CSK))
+ return true;
+ if (isBetterOverloadCandidate(S, *R, *L, SourceLocation(), CSK))
+ return false;
} else if (R->Viable)
return false;
@@ -10446,8 +10518,8 @@ void OverloadCandidateSet::NoteCandidates(
}
}
- std::sort(Cands.begin(), Cands.end(),
- CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size()));
+ std::stable_sort(Cands.begin(), Cands.end(),
+ CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
bool ReportedAmbiguousConversions = false;
@@ -10627,7 +10699,7 @@ static bool completeFunctionType(Sema &S, FunctionDecl *FD, SourceLocation Loc,
return true;
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
- if (S.getLangOpts().CPlusPlus1z &&
+ if (S.getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
!S.ResolveExceptionSpec(Loc, FPT))
return true;
@@ -11878,7 +11950,7 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
ExprResult
Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *Input) {
+ Expr *Input, bool PerformADL) {
OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -11929,9 +12001,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
- /*ExplicitTemplateArgs*/nullptr,
- CandidateSet);
+ if (PerformADL) {
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+ /*ExplicitTemplateArgs*/nullptr,
+ CandidateSet);
+ }
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -12069,7 +12143,7 @@ ExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS) {
+ Expr *LHS, Expr *RHS, bool PerformADL) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
@@ -12100,7 +12174,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, NamingClass,
NestedNameSpecifierLoc(), OpNameInfo,
- /*ADL*/ true, IsOverloaded(Fns),
+ /*ADL*/PerformADL, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return new (Context)
CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
@@ -12143,7 +12217,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
// performed for an assignment operator (nor for operator[] nor operator->,
// which don't get here).
- if (Opc != BO_Assign)
+ if (Opc != BO_Assign && PerformADL)
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ nullptr,
CandidateSet);
@@ -12896,7 +12970,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(),
- Best)) {
+ Best)) {
case OR_Success:
// Overload resolution succeeded; we'll build the appropriate call
// below.
@@ -13290,7 +13364,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
Expr *Range, ExprResult *CallExpr) {
Scope *S = nullptr;
- CandidateSet->clear();
+ CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
if (!MemberLookup.empty()) {
ExprResult MemberRef =
BuildMemberReferenceExpr(Range, Range->getType(), Loc,
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index d159172a6990..58980be64a30 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -1442,8 +1442,7 @@ MSPropertyOpBuilder::getBaseMSProperty(MSPropertySubscriptExpr *E) {
Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
InstanceBase = capture(RefExpr->getBaseExpr());
- std::for_each(CallArgs.begin(), CallArgs.end(),
- [this](Expr *&Arg) { Arg = capture(Arg); });
+ llvm::for_each(CallArgs, [this](Expr *&Arg) { Arg = capture(Arg); });
syntacticBase = Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * {
switch (Idx) {
case 0:
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 2a38a1f8e1d8..ff0f4d995851 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -127,34 +127,47 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
/// warning from firing.
static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
SourceLocation Loc;
- bool IsNotEqual, CanAssign, IsRelational;
+ bool CanAssign;
+ enum { Equality, Inequality, Relational, ThreeWay } Kind;
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
if (!Op->isComparisonOp())
return false;
- IsRelational = Op->isRelationalOp();
+ if (Op->getOpcode() == BO_EQ)
+ Kind = Equality;
+ else if (Op->getOpcode() == BO_NE)
+ Kind = Inequality;
+ else if (Op->getOpcode() == BO_Cmp)
+ Kind = ThreeWay;
+ else {
+ assert(Op->isRelationalOp());
+ Kind = Relational;
+ }
Loc = Op->getOperatorLoc();
- IsNotEqual = Op->getOpcode() == BO_NE;
CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue();
} else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
switch (Op->getOperator()) {
- default:
- return false;
case OO_EqualEqual:
+ Kind = Equality;
+ break;
case OO_ExclaimEqual:
- IsRelational = false;
+ Kind = Inequality;
break;
case OO_Less:
case OO_Greater:
case OO_GreaterEqual:
case OO_LessEqual:
- IsRelational = true;
+ Kind = Relational;
+ break;
+ case OO_Spaceship:
+ Kind = ThreeWay;
break;
+ default:
+ return false;
}
Loc = Op->getOperatorLoc();
- IsNotEqual = Op->getOperator() == OO_ExclaimEqual;
CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue();
} else {
// Not a typo-prone comparison.
@@ -167,15 +180,15 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return false;
S.Diag(Loc, diag::warn_unused_comparison)
- << (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange();
+ << (unsigned)Kind << E->getSourceRange();
// If the LHS is a plausible entity to assign to, provide a fixit hint to
// correct common typos.
- if (!IsRelational && CanAssign) {
- if (IsNotEqual)
+ if (CanAssign) {
+ if (Kind == Inequality)
S.Diag(Loc, diag::note_inequality_comparison_to_or_assign)
<< FixItHint::CreateReplacement(Loc, "|=");
- else
+ else if (Kind == Equality)
S.Diag(Loc, diag::note_equality_comparison_to_assign)
<< FixItHint::CreateReplacement(Loc, "=");
}
@@ -602,14 +615,14 @@ static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs,
/// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of
/// potentially integral-promoted expression @p expr.
-static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) {
- if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr))
- expr = cleanups->getSubExpr();
- while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) {
- if (impcast->getCastKind() != CK_IntegralCast) break;
- expr = impcast->getSubExpr();
+static QualType GetTypeBeforeIntegralPromotion(const Expr *&E) {
+ if (const auto *CleanUps = dyn_cast<ExprWithCleanups>(E))
+ E = CleanUps->getSubExpr();
+ while (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ImpCast->getCastKind() != CK_IntegralCast) break;
+ E = ImpCast->getSubExpr();
}
- return expr->getType();
+ return E->getType();
}
ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) {
@@ -743,6 +756,32 @@ static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,
return true;
}
+static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond,
+ const Expr *Case) {
+ QualType CondType = GetTypeBeforeIntegralPromotion(Cond);
+ QualType CaseType = Case->getType();
+
+ const EnumType *CondEnumType = CondType->getAs<EnumType>();
+ const EnumType *CaseEnumType = CaseType->getAs<EnumType>();
+ if (!CondEnumType || !CaseEnumType)
+ return;
+
+ // Ignore anonymous enums.
+ if (!CondEnumType->getDecl()->getIdentifier() &&
+ !CondEnumType->getDecl()->getTypedefNameForAnonDecl())
+ return;
+ if (!CaseEnumType->getDecl()->getIdentifier() &&
+ !CaseEnumType->getDecl()->getTypedefNameForAnonDecl())
+ return;
+
+ if (S.Context.hasSameUnqualifiedType(CondType, CaseType))
+ return;
+
+ S.Diag(Case->getExprLoc(), diag::warn_comparison_of_mixed_enum_types_switch)
+ << CondType << CaseType << Cond->getSourceRange()
+ << Case->getSourceRange();
+}
+
StmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Stmt *BodyStmt) {
@@ -760,7 +799,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
QualType CondType = CondExpr->getType();
- Expr *CondExprBeforePromotion = CondExpr;
+ const Expr *CondExprBeforePromotion = CondExpr;
QualType CondTypeBeforePromotion =
GetTypeBeforeIntegralPromotion(CondExprBeforePromotion);
@@ -843,6 +882,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
break;
}
+ checkEnumTypesInSwitchStmt(*this, CondExpr, Lo);
+
llvm::APSInt LoVal;
if (getLangOpts().CPlusPlus11) {
@@ -2452,7 +2493,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// C++1z removes this restriction.
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
- Diag(RangeLoc, getLangOpts().CPlusPlus1z
+ Diag(RangeLoc, getLangOpts().CPlusPlus17
? diag::warn_for_range_begin_end_types_differ
: diag::ext_for_range_begin_end_types_differ)
<< BeginType << EndType;
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index c182b35bfad4..fc1cc7bbe544 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -48,10 +48,10 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
if (E != E2 && E2->isLValue()) {
if (!S.getLangOpts().HeinousExtensions)
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
- << E->getSourceRange();
+ << E->getSourceRange();
else
S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
- << E->getSourceRange();
+ << E->getSourceRange();
// Accept, even if we emitted an error diagnostic.
return false;
}
@@ -62,11 +62,13 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
/// isOperandMentioned - Return true if the specified operand # is mentioned
/// anywhere in the decomposed asm string.
-static bool isOperandMentioned(unsigned OpNo,
- ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
+static bool
+isOperandMentioned(unsigned OpNo,
+ ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) {
for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
- if (!Piece.isOperand()) continue;
+ if (!Piece.isOperand())
+ continue;
// If this is a reference to the input and if the input was the smaller
// one, then we have to reject this asm.
@@ -605,23 +607,31 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return NS;
}
-static void fillInlineAsmTypeInfo(const ASTContext &Context, QualType T,
- llvm::InlineAsmIdentifierInfo &Info) {
- // Compute the type size (and array length if applicable?).
- Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity();
- if (T->isArrayType()) {
- const ArrayType *ATy = Context.getAsArrayType(T);
- Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
- Info.Length = Info.Size / Info.Type;
+void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
+ llvm::InlineAsmIdentifierInfo &Info) {
+ QualType T = Res->getType();
+ Expr::EvalResult Eval;
+ if (T->isFunctionType() || T->isDependentType())
+ return Info.setLabel(Res);
+ if (Res->isRValue()) {
+ if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context))
+ return Info.setEnum(Eval.Val.getInt().getSExtValue());
+ return Info.setLabel(Res);
}
+ unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
+ unsigned Type = Size;
+ if (const auto *ATy = Context.getAsArrayType(T))
+ Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
+ bool IsGlobalLV = false;
+ if (Res->EvaluateAsLValue(Eval, Context))
+ IsGlobalLV = Eval.isGlobalLValue();
+ Info.setVar(Res, IsGlobalLV, Size, Type);
}
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
- llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) {
- Info.clear();
if (IsUnevaluatedContext)
PushExpressionEvaluationContext(
@@ -662,12 +672,6 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
return ExprError();
}
- fillInlineAsmTypeInfo(Context, T, Info);
-
- // We can work with the expression as long as it's not an r-value.
- if (!Result.get()->isRValue())
- Info.IsVarDecl = true;
-
return Result;
}
@@ -677,22 +681,33 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
SmallVector<StringRef, 2> Members;
Member.split(Members, ".");
- LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
- LookupOrdinaryName);
+ NamedDecl *FoundDecl = nullptr;
- if (!LookupName(BaseResult, getCurScope()))
- return true;
-
- if(!BaseResult.isSingleResult())
+ // MS InlineAsm uses 'this' as a base
+ if (getLangOpts().CPlusPlus && Base.equals("this")) {
+ if (const Type *PT = getCurrentThisType().getTypePtrOrNull())
+ FoundDecl = PT->getPointeeType()->getAsTagDecl();
+ } else {
+ LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(),
+ LookupOrdinaryName);
+ if (LookupName(BaseResult, getCurScope()) && BaseResult.isSingleResult())
+ FoundDecl = BaseResult.getFoundDecl();
+ }
+
+ if (!FoundDecl)
return true;
- NamedDecl *FoundDecl = BaseResult.getFoundDecl();
+
for (StringRef NextMember : Members) {
const RecordType *RT = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
RT = VD->getType()->getAs<RecordType>();
else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
- RT = TD->getUnderlyingType()->getAs<RecordType>();
+ // MS InlineAsm often uses struct pointer aliases as a base
+ QualType QT = TD->getUnderlyingType();
+ if (const auto *PT = QT->getAs<PointerType>())
+ QT = PT->getPointeeType();
+ RT = QT->getAs<RecordType>();
} else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
RT = TD->getTypeForDecl()->getAs<RecordType>();
else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl))
@@ -730,9 +745,7 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
ExprResult
Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
- llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc) {
- Info.clear();
QualType T = E->getType();
if (T->isDependentType()) {
@@ -767,14 +780,6 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
ExprResult Result = BuildMemberReferenceExpr(
E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
SourceLocation(), nullptr, FieldResult, nullptr, nullptr);
- if (Result.isInvalid())
- return Result;
- Info.OpDecl = Result.get();
-
- fillInlineAsmTypeInfo(Context, Result.get()->getType(), Info);
-
- // Fields are "variables" as far as inline assembly is concerned.
- Info.IsVarDecl = true;
return Result;
}
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 4ee3412170a8..e55e20c2827f 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -43,11 +43,11 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
return nullptr;
}
- // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // If this is spelled as the standard C++17 attribute, but not in C++17, warn
// about using it as an extension.
- if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() &&
+ if (!S.getLangOpts().CPlusPlus17 && A.isCXX11Attribute() &&
!A.getScopeName())
- S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName();
+ S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A.getName();
FnScope->setHasFallthroughStmt();
return ::new (S.Context) auto(Attr);
@@ -100,16 +100,15 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
return nullptr;
}
- LoopHintAttr::Spelling Spelling;
+ LoopHintAttr::Spelling Spelling =
+ LoopHintAttr::Spelling(A.getAttributeSpellingListIndex());
LoopHintAttr::OptionType Option;
LoopHintAttr::LoopHintState State;
if (PragmaNoUnroll) {
// #pragma nounroll
- Spelling = LoopHintAttr::Pragma_nounroll;
Option = LoopHintAttr::Unroll;
State = LoopHintAttr::Disable;
} else if (PragmaUnroll) {
- Spelling = LoopHintAttr::Pragma_unroll;
if (ValueExpr) {
// #pragma unroll N
Option = LoopHintAttr::UnrollCount;
@@ -121,7 +120,6 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
}
} else {
// #pragma clang loop ...
- Spelling = LoopHintAttr::Pragma_clang_loop;
assert(OptionLoc && OptionLoc->Ident &&
"Attribute must have valid option info.");
Option = llvm::StringSwitch<LoopHintAttr::OptionType>(
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index e9b38551683c..c70a8ba8f126 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -778,7 +778,7 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
SourceLocation Loc,
IdentifierInfo *Name) {
NamedDecl *PrevDecl = SemaRef.LookupSingleName(
- S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter())
SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl);
}
@@ -1080,7 +1080,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ArrayRef<Decl *> Params,
+ ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
Expr *RequiresClause) {
if (ExportLoc.isValid())
@@ -1088,7 +1088,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
return TemplateParameterList::Create(
Context, TemplateLoc, LAngleLoc,
- llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()),
+ llvm::makeArrayRef(Params.data(), Params.size()),
RAngleLoc, RequiresClause);
}
@@ -1133,7 +1133,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
LookupResult Previous(*this, Name, NameLoc,
(SS.isEmpty() && TUK == TUK_Friend)
? LookupTagName : LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
@@ -1192,8 +1192,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
- ClassTemplateDecl *PrevClassTemplate
- = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
+ ClassTemplateDecl *PrevClassTemplate =
+ dyn_cast_or_null<ClassTemplateDecl>(PrevDecl);
// We may have found the injected-class-name of a class template,
// class template partial specialization, or class template specialization.
@@ -1484,6 +1484,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
CurContext->addDecl(Friend);
}
+ if (PrevClassTemplate)
+ CheckRedeclarationModuleOwnership(NewTemplate, PrevClassTemplate);
+
if (Invalid) {
NewTemplate->setInvalidDecl();
NewClass->setInvalidDecl();
@@ -1834,7 +1837,6 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
// for which some class template parameter without a default argument never
// appears in a deduced context).
bool AddedAny = false;
- bool AddedCopyOrMove = false;
for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
D = D->getUnderlyingDecl();
if (D->isInvalidDecl() || D->isImplicit())
@@ -1851,20 +1853,22 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
Transform.transformConstructor(FTD, CD);
AddedAny = true;
-
- AddedCopyOrMove |= CD->isCopyOrMoveConstructor();
}
- // Synthesize an X() -> X<...> guide if there were no declared constructors.
- // FIXME: The standard doesn't say (how) to do this.
+ // C++17 [over.match.class.deduct]
+ // -- If C is not defined or does not declare any constructors, an
+ // additional function template derived as above from a hypothetical
+ // constructor C().
if (!AddedAny)
Transform.buildSimpleDeductionGuide(None);
- // Synthesize an X(X<...>) -> X<...> guide if there was no declared constructor
- // resembling a copy or move constructor.
- // FIXME: The standard doesn't say (how) to do this.
- if (!AddedCopyOrMove)
- Transform.buildSimpleDeductionGuide(Transform.DeducedType);
+ // -- An additional function template derived as above from a hypothetical
+ // constructor C(C), called the copy deduction candidate.
+ cast<CXXDeductionGuideDecl>(
+ cast<FunctionTemplateDecl>(
+ Transform.buildSimpleDeductionGuide(Transform.DeducedType))
+ ->getTemplatedDecl())
+ ->setIsCopyDeductionCandidate();
}
/// \brief Diagnose the presence of a default template argument on a
@@ -2863,11 +2867,9 @@ static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) {
return Cond;
}
-/// Find the failed subexpression within enable_if, and describe it
-/// with a string.
-static std::pair<Expr *, std::string>
-findFailedEnableIfCondition(Sema &S, Expr *Cond) {
- Cond = lookThroughRangesV3Condition(S.PP, Cond);
+std::pair<Expr *, std::string>
+Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
+ Cond = lookThroughRangesV3Condition(PP, Cond);
// Separate out all of the terms in a conjunction.
SmallVector<Expr *, 4> Terms;
@@ -2876,27 +2878,37 @@ findFailedEnableIfCondition(Sema &S, Expr *Cond) {
// Determine which term failed.
Expr *FailedCond = nullptr;
for (Expr *Term : Terms) {
+ Expr *TermAsWritten = Term->IgnoreParenImpCasts();
+
+ // Literals are uninteresting.
+ if (isa<CXXBoolLiteralExpr>(TermAsWritten) ||
+ isa<IntegerLiteral>(TermAsWritten))
+ continue;
+
// The initialization of the parameter from the argument is
// a constant-evaluated context.
EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
bool Succeeded;
- if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) &&
+ if (Term->EvaluateAsBooleanCondition(Succeeded, Context) &&
!Succeeded) {
- FailedCond = Term->IgnoreParenImpCasts();
+ FailedCond = TermAsWritten;
break;
}
}
- if (!FailedCond)
+ if (!FailedCond) {
+ if (!AllowTopLevelCond)
+ return { nullptr, "" };
+
FailedCond = Cond->IgnoreParenImpCasts();
+ }
std::string Description;
{
llvm::raw_string_ostream Out(Description);
- FailedCond->printPretty(Out, nullptr,
- PrintingPolicy(S.Context.getLangOpts()));
+ FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
}
return { FailedCond, Description };
}
@@ -2980,8 +2992,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Expr *FailedCond;
std::string FailedDescription;
std::tie(FailedCond, FailedDescription) =
- findFailedEnableIfCondition(
- *this, TemplateArgs[0].getSourceExpression());
+ findFailedBooleanCondition(
+ TemplateArgs[0].getSourceExpression(),
+ /*AllowTopLevelCond=*/true);
// Remove the old SFINAE diagnostic.
PartialDiagnosticAt OldDiag =
@@ -3668,7 +3681,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Check that this isn't a redefinition of this specialization,
// merging with previous declarations.
LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName,
- ForRedeclaration);
+ forRedeclarationInCurContext());
PrevSpec.addDecl(PrevDecl);
D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
} else if (Specialization->isStaticDataMember() &&
@@ -4792,7 +4805,12 @@ bool Sema::CheckTemplateArgumentList(
// template.
TemplateArgumentListInfo NewArgs = TemplateArgs;
- TemplateParameterList *Params = Template->getTemplateParameters();
+ // Make sure we get the template parameter list from the most
+ // recentdeclaration, since that is the only one that has is guaranteed to
+ // have all the default template argument information.
+ TemplateParameterList *Params =
+ cast<TemplateDecl>(Template->getMostRecentDecl())
+ ->getTemplateParameters();
SourceLocation RAngleLoc = NewArgs.getRAngleLoc();
@@ -5116,6 +5134,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType(
return Visit(T->getElementType());
}
+bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType(
+ const DependentAddressSpaceType *T) {
+ return Visit(T->getPointeeType());
+}
+
bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) {
return Visit(T->getElementType());
}
@@ -5900,7 +5923,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
SourceLocation StartLoc = Arg->getLocStart();
// If the parameter type somehow involves auto, deduce the type now.
- if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) {
+ if (getLangOpts().CPlusPlus17 && ParamType->isUndeducedType()) {
// During template argument deduction, we allow 'decltype(auto)' to
// match an arbitrary dependent argument.
// FIXME: The language rules don't say what happens in this case.
@@ -5984,8 +6007,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
EnterExpressionEvaluationContext ConstantEvaluated(
*this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- if (getLangOpts().CPlusPlus1z) {
- // C++1z [temp.arg.nontype]p1:
+ if (getLangOpts().CPlusPlus17) {
+ // C++17 [temp.arg.nontype]p1:
// A template-argument for a non-type template parameter shall be
// a converted constant expression of the type of the template-parameter.
APValue Value;
@@ -6152,7 +6175,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- an integral constant-expression of integral or enumeration
// type; or
// -- the name of a non-type template-parameter; or
- SourceLocation NonConstantLoc;
llvm::APSInt Value;
if (!ArgType->isIntegralOrEnumerationType()) {
Diag(Arg->getLocStart(),
@@ -8015,15 +8037,6 @@ bool Sema::CheckFunctionTemplateSpecialization(
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
- // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...]
- // an explicit specialization (14.8.3) [...] of a concept definition.
- if (Specialization->getPrimaryTemplate()->isConcept()) {
- Diag(FD->getLocation(), diag::err_concept_specialized)
- << 0 /*function*/ << 1 /*explicitly specialized*/;
- Diag(Specialization->getLocation(), diag::note_previous_declaration);
- return true;
- }
-
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
@@ -8910,15 +8923,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
Diag(D.getDeclSpec().getConstexprSpecLoc(),
diag::err_explicit_instantiation_constexpr);
- // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
- // applied only to the definition of a function template or variable template,
- // declared in namespace scope.
- if (D.getDeclSpec().isConceptSpecified()) {
- Diag(D.getDeclSpec().getConceptSpecLoc(),
- diag::err_concept_specified_specialization) << 0;
- return true;
- }
-
// A deduction guide is not on the list of entities that can be explicitly
// instantiated.
if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
@@ -8998,15 +9002,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
- // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an
- // explicit instantiation (14.8.2) [...] of a concept definition.
- if (PrevTemplate->isConcept()) {
- Diag(D.getIdentifierLoc(), diag::err_concept_specialized)
- << 1 /*variable*/ << 0 /*explicitly instantiated*/;
- Diag(PrevTemplate->getLocation(), diag::note_previous_declaration);
- return true;
- }
-
// Translate the parser's template argument list into our AST format.
TemplateArgumentListInfo TemplateArgs =
makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
@@ -9049,7 +9044,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!HasNoEffect) {
// Instantiate static data member or variable template.
-
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (PrevTemplate) {
// Merge attributes.
@@ -9217,10 +9211,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return (Decl*) nullptr;
}
- Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
+ // In MSVC mode, dllimported explicit instantiation definitions are treated as
+ // instantiation declarations.
+ if (TSK == TSK_ExplicitInstantiationDefinition &&
+ Specialization->hasAttr<DLLImportAttr>() &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft())
+ TSK = TSK_ExplicitInstantiationDeclaration;
+
+ Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
+
if (Specialization->isDefined()) {
// Let the ASTConsumer know that this function has been explicitly
// instantiated now, and its linkage might have changed.
@@ -9243,16 +9245,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::ext_explicit_instantiation_without_qualified_id)
<< Specialization << D.getCXXScopeSpec().getRange();
- // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an
- // explicit instantiation (14.8.2) [...] of a concept definition.
- if (FunTmpl && FunTmpl->isConcept() &&
- !D.getDeclSpec().isConceptSpecified()) {
- Diag(D.getIdentifierLoc(), diag::err_concept_specialized)
- << 0 /*function*/ << 0 /*explicitly instantiated*/;
- Diag(FunTmpl->getLocation(), diag::note_previous_declaration);
- return true;
- }
-
CheckExplicitInstantiationScope(*this,
FunTmpl? (NamedDecl *)FunTmpl
: Specialization->getInstantiatedFromMemberFunction(),
@@ -9513,7 +9505,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
Expr *FailedCond;
std::string FailedDescription;
std::tie(FailedCond, FailedDescription) =
- findFailedEnableIfCondition(*this, Cond);
+ findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
Diag(FailedCond->getExprLoc(),
diag::err_typename_nested_not_found_requirement)
@@ -9591,7 +9583,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// A type-specifier of the form
// typename[opt] nested-name-specifier[opt] template-name
// is a placeholder for a deduced class type [...].
- if (getLangOpts().CPlusPlus1z) {
+ if (getLangOpts().CPlusPlus17) {
if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) {
return Context.getElaboratedType(
Keyword, QualifierLoc.getNestedNameSpecifier(),
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 983b1ea795dd..564692b03020 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -344,7 +344,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
}
Deduced[NTTP->getIndex()] = Result;
- if (!S.getLangOpts().CPlusPlus1z)
+ if (!S.getLangOpts().CPlusPlus17)
return Sema::TDK_Success;
if (NTTP->isExpandedParameterPack())
@@ -354,8 +354,9 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
// expanded NTTP should be a pack expansion type?
return Sema::TDK_Success;
- // Get the type of the parameter for deduction.
- QualType ParamType = NTTP->getType();
+ // Get the type of the parameter for deduction. If it's a (dependent) array
+ // or function type, we will not have decayed it yet, so do that now.
+ QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType());
if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
ParamType = Expansion->getPattern();
@@ -1843,6 +1844,59 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
}
+ // (clang extension)
+ //
+ // T __attribute__(((address_space(N))))
+ case Type::DependentAddressSpace: {
+ const DependentAddressSpaceType *AddressSpaceParam =
+ cast<DependentAddressSpaceType>(Param);
+
+ if (const DependentAddressSpaceType *AddressSpaceArg =
+ dyn_cast<DependentAddressSpaceType>(Arg)) {
+ // Perform deduction on the pointer type.
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, AddressSpaceParam->getPointeeType(),
+ AddressSpaceArg->getPointeeType(), Info, Deduced, TDF))
+ return Result;
+
+ // Perform deduction on the address space, if we can.
+ NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+ Info, AddressSpaceParam->getAddrSpaceExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info,
+ Deduced);
+ }
+
+ if (isTargetAddressSpace(Arg.getAddressSpace())) {
+ llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy),
+ false);
+ ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace());
+
+ // Perform deduction on the pointer types.
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, AddressSpaceParam->getPointeeType(),
+ S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF))
+ return Result;
+
+ // Perform deduction on the address space, if we can.
+ NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+ Info, AddressSpaceParam->getAddrSpaceExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
+ ArgAddressSpace, S.Context.IntTy,
+ true, Info, Deduced);
+ }
+
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
@@ -2695,6 +2749,17 @@ static bool isSimpleTemplateIdType(QualType T) {
= T->getAs<TemplateSpecializationType>())
return Spec->getTemplateName().getAsTemplateDecl() != nullptr;
+ // C++17 [temp.local]p2:
+ // the injected-class-name [...] is equivalent to the template-name followed
+ // by the template-arguments of the class template specialization or partial
+ // specialization enclosed in <>
+ // ... which means it's equivalent to a simple-template-id.
+ //
+ // This only arises during class template argument deduction for a copy
+ // deduction candidate, where it permits slicing.
+ if (T->getAs<InjectedClassNameType>())
+ return true;
+
return false;
}
@@ -2869,7 +2934,7 @@ Sema::SubstituteExplicitTemplateArguments(
// so substitution into the type must also substitute into the exception
// specification.
SmallVector<QualType, 4> ExceptionStorage;
- if (getLangOpts().CPlusPlus1z &&
+ if (getLangOpts().CPlusPlus17 &&
SubstExceptionSpec(
Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
@@ -2907,17 +2972,26 @@ Sema::SubstituteExplicitTemplateArguments(
/// \brief Check whether the deduced argument type for a call to a function
/// template matches the actual argument type per C++ [temp.deduct.call]p4.
-static bool
-CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
+static Sema::TemplateDeductionResult
+CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info,
+ Sema::OriginalCallArg OriginalArg,
QualType DeducedA) {
ASTContext &Context = S.Context;
+ auto Failed = [&]() -> Sema::TemplateDeductionResult {
+ Info.FirstArg = TemplateArgument(DeducedA);
+ Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
+ Info.CallArgIndex = OriginalArg.ArgIdx;
+ return OriginalArg.DecomposedParam ? Sema::TDK_DeducedMismatchNested
+ : Sema::TDK_DeducedMismatch;
+ };
+
QualType A = OriginalArg.OriginalArgType;
QualType OriginalParamType = OriginalArg.OriginalParamType;
// Check for type equality (top-level cv-qualifiers are ignored).
if (Context.hasSameUnqualifiedType(A, DeducedA))
- return false;
+ return Sema::TDK_Success;
// Strip off references on the argument types; they aren't needed for
// the following checks.
@@ -2941,7 +3015,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
// the deduced A can be F.
QualType Tmp;
if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp))
- return false;
+ return Sema::TDK_Success;
Qualifiers AQuals = A.getQualifiers();
Qualifiers DeducedAQuals = DeducedA.getQualifiers();
@@ -2961,7 +3035,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
if (AQuals == DeducedAQuals) {
// Qualifiers match; there's nothing to do.
} else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
- return true;
+ return Failed();
} else {
// Qualifiers are compatible, so have the argument type adopt the
// deduced argument type's qualifiers as if we had performed the
@@ -2982,7 +3056,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
(S.IsQualificationConversion(A, DeducedA, false,
ObjCLifetimeConversion) ||
S.IsFunctionConversion(A, DeducedA, ResultTy)))
- return false;
+ return Sema::TDK_Success;
// - If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. [...]
@@ -3003,13 +3077,13 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
}
if (Context.hasSameUnqualifiedType(A, DeducedA))
- return false;
+ return Sema::TDK_Success;
if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
S.IsDerivedFrom(SourceLocation(), A, DeducedA))
- return false;
+ return Sema::TDK_Success;
- return true;
+ return Failed();
}
/// Find the pack index for a particular parameter index in an instantiation of
@@ -3165,13 +3239,9 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
DeducedA = CacheEntry;
}
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
- Info.FirstArg = TemplateArgument(DeducedA);
- Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
- Info.CallArgIndex = OriginalArg.ArgIdx;
- return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested
- : TDK_DeducedMismatch;
- }
+ if (auto TDK =
+ CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA))
+ return TDK;
}
}
@@ -3838,7 +3908,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// so we can check that the exception specification matches.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
- if (getLangOpts().CPlusPlus1z &&
+ if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TDK_MiscellaneousDeductionFailure;
@@ -4231,6 +4301,31 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
DependentDeductionDepth);
}
+/// Attempt to produce an informative diagostic explaining why auto deduction
+/// failed.
+/// \return \c true if diagnosed, \c false if not.
+static bool diagnoseAutoDeductionFailure(Sema &S,
+ Sema::TemplateDeductionResult TDK,
+ TemplateDeductionInfo &Info,
+ ArrayRef<SourceRange> Ranges) {
+ switch (TDK) {
+ case Sema::TDK_Inconsistent: {
+ // Inconsistent deduction means we were deducing from an initializer list.
+ auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
+ D << Info.FirstArg << Info.SecondArg;
+ for (auto R : Ranges)
+ D << R;
+ return true;
+ }
+
+ // FIXME: Are there other cases for which a custom diagnostic is more useful
+ // than the basic "types don't match" diagnostic?
+
+ default:
+ return false;
+ }
+}
+
/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// Note that this is done even if the initializer is dependent. (This is
@@ -4318,12 +4413,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
- auto DeductionFailed = [&]() -> DeduceAutoResult {
+ auto DeductionFailed = [&](TemplateDeductionResult TDK,
+ ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
if (Init->isTypeDependent()) {
Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
+ if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
+ return DAR_FailedAlreadyDiagnosed;
return DAR_Failed;
};
@@ -4337,12 +4435,20 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
return DAR_Failed;
+ SourceRange DeducedFromInitRange;
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- if (DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i),
+ Expr *Init = InitList->getInit(i);
+
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, TemplArg, Init,
Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
/*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed();
+ return DeductionFailed(TDK, {DeducedFromInitRange,
+ Init->getSourceRange()});
+
+ if (DeducedFromInitRange.isInvalid() &&
+ Deduced[0].getKind() != TemplateArgument::Null)
+ DeducedFromInitRange = Init->getSourceRange();
}
} else {
if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
@@ -4350,15 +4456,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
- if (DeduceTemplateArgumentsFromCallArgument(
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed();
+ return DeductionFailed(TDK, {});
}
// Could be null if somehow 'auto' appears in a non-deduced context.
if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed();
+ return DeductionFailed(TDK_Incomplete, {});
QualType DeducedType = Deduced[0].getAsType();
@@ -4378,9 +4484,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
assert((bool)InitList == OriginalArg.DecomposedParam &&
"decomposed non-init-list in auto deduction?");
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
+ if (auto TDK =
+ CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
- return DeductionFailed();
+ return DeductionFailed(TDK, {});
}
}
@@ -5045,9 +5152,9 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
- // In C++1z mode, additional arguments may be deduced from the type of a
+ // In C++17 mode, additional arguments may be deduced from the type of a
// non-type argument.
- if (Ctx.getLangOpts().CPlusPlus1z)
+ if (Ctx.getLangOpts().CPlusPlus17)
MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
}
@@ -5174,6 +5281,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
break;
}
+ case Type::DependentAddressSpace: {
+ const DependentAddressSpaceType *DependentASType =
+ cast<DependentAddressSpaceType>(T);
+ MarkUsedTemplateParameters(Ctx, DependentASType->getPointeeType(),
+ OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx,
+ DependentASType->getAddrSpaceExpr(),
+ OnlyDeduced, Depth, Used);
+ break;
+ }
+
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth,
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index f4f0c804aee1..a48e2466a84d 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -496,8 +496,8 @@ void Sema::PrintInstantiationStack() {
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
Template->printName(OS);
- TemplateSpecializationType::PrintTemplateArgumentList(
- OS, Active->template_arguments(), getPrintingPolicy());
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_arg_instantiation_here)
<< OS.str()
@@ -562,8 +562,8 @@ void Sema::PrintInstantiationStack() {
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
FD->printName(OS);
- TemplateSpecializationType::PrintTemplateArgumentList(
- OS, Active->template_arguments(), getPrintingPolicy());
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_function_arg_instantiation_here)
<< OS.str()
@@ -975,7 +975,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
return Template.getAsTemplateDecl();
@@ -1122,14 +1122,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
assert(!Template.isNull() && "Null template template argument");
-
- // We don't ever want to substitute for a qualified template name, since
- // the qualifier is handled separately. So, look through the qualified
- // template name to its underlying declaration.
- if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- Template = TemplateName(QTN->getTemplateDecl());
+ assert(!Template.getAsQualifiedTemplateName() &&
+ "template decl to substitute is qualified?");
Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
return Template;
@@ -1143,7 +1139,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(
TemplateArgument Arg = SubstPack->getArgumentPack();
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return Arg.getAsTemplate();
+ return Arg.getAsTemplate().getNameToSubstitute();
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
@@ -2030,12 +2026,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod();
LocalInstantiationScope Scope(*this, MergeWithParentScope);
- // All dllexported classes created during instantiation should be fully
- // emitted after instantiation completes. We may not be ready to emit any
- // delayed classes already on the stack, so save them away and put them back
- // later.
- decltype(DelayedDllExportClasses) ExportedClasses;
- std::swap(ExportedClasses, DelayedDllExportClasses);
+ // Some class state isn't processed immediately but delayed till class
+ // instantiation completes. We may not be ready to handle any delayed state
+ // already on the stack as it might correspond to a different class, so save
+ // it now and put it back later.
+ SavePendingParsedClassStateRAII SavedPendingParsedClassState(*this);
// Pull attributes from the pattern onto the instantiation.
InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
@@ -2122,9 +2117,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// default arg exprs for default constructors if necessary now.
ActOnFinishCXXNonNestedClass(Instantiation);
- // Put back the delayed exported classes that we moved out of the way.
- std::swap(ExportedClasses, DelayedDllExportClasses);
-
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
@@ -2621,7 +2613,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
continue;
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
} else {
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4a26efcc9431..f627f6017f38 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1195,7 +1195,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Look for a previous declaration of the template in the owning
// context.
LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(),
- Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ Sema::LookupOrdinaryName,
+ SemaRef.forRedeclarationInCurContext());
SemaRef.LookupQualifiedName(R, DC);
if (R.isSingleResult()) {
@@ -1650,11 +1651,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
FunctionDecl *Function;
- if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D))
+ if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
Function = CXXDeductionGuideDecl::Create(
- SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
- D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd());
- else {
+ SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
+ D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd());
+ if (DGuide->isCopyDeductionCandidate())
+ cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
+ } else {
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
@@ -1685,7 +1688,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params[P]->setOwningFunction(Function);
Function->setParams(Params);
- SourceLocation InstantiateAtPOI;
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -1736,7 +1738,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
SemaRef, Function->getDeclName(), SourceLocation(),
D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ D->isLocalExternDecl() ? Sema::ForExternalRedeclaration
+ : SemaRef.forRedeclarationInCurContext());
if (DependentFunctionTemplateSpecializationInfo *Info
= D->getDependentSpecializationInfo()) {
@@ -2054,7 +2057,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setInvalidDecl();
LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ Sema::ForExternalRedeclaration);
if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
@@ -2493,7 +2496,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
bool CheckRedeclaration = Owner->isRecord();
LookupResult Prev(SemaRef, NameInfo, Sema::LookupUsingDeclName,
- Sema::ForRedeclaration);
+ Sema::ForVisibleRedeclaration);
UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner,
D->getUsingLoc(),
@@ -2712,7 +2715,7 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
return nullptr;
LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ Sema::ForExternalRedeclaration);
TemplateArgumentListInfo TemplateArgs;
TemplateArgumentListInfo *TemplateArgsPtr = nullptr;
@@ -2800,8 +2803,9 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
// Initializers instantiation sequence.
if (D->getInitializer()) {
- SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
- /*S=*/nullptr, NewDRD);
+ VarDecl *OmpPrivParm =
+ SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
+ /*S=*/nullptr, NewDRD);
const char *Names[] = {"omp_orig", "omp_priv"};
for (auto &Name : Names) {
DeclarationName DN(&SemaRef.Context.Idents.get(Name));
@@ -2809,17 +2813,28 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
auto Lookup = NewDRD->lookup(DN);
if (!OldLookup.empty() && !Lookup.empty()) {
assert(Lookup.size() == 1 && OldLookup.size() == 1);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- OldLookup.front(), Lookup.front());
+ auto *OldVD = cast<VarDecl>(OldLookup.front());
+ auto *NewVD = cast<VarDecl>(Lookup.front());
+ SemaRef.InstantiateVariableInitializer(NewVD, OldVD, TemplateArgs);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldVD, NewVD);
}
}
- SubstInitializer =
- SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
- SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD,
- SubstInitializer);
+ if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) {
+ SubstInitializer =
+ SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
+ } else {
+ IsCorrect = IsCorrect && OmpPrivParm->hasInit();
+ }
+ SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(
+ NewDRD, SubstInitializer, OmpPrivParm);
}
- IsCorrect = IsCorrect && SubstCombiner &&
- (!D->getInitializer() || SubstInitializer);
+ IsCorrect =
+ IsCorrect && SubstCombiner &&
+ (!D->getInitializer() ||
+ (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit &&
+ SubstInitializer) ||
+ (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit &&
+ !SubstInitializer && !SubstInitializer));
} else
IsCorrect = false;
@@ -3753,7 +3768,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
bool Recursive,
bool DefinitionRequired,
bool AtEndOfTU) {
- if (Function->isInvalidDecl() || Function->isDefined())
+ if (Function->isInvalidDecl() || Function->isDefined() ||
+ isa<CXXDeductionGuideDecl>(Function))
return;
// Never instantiate an explicit specialization except if it is a class scope
@@ -4005,6 +4021,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl,
const MultiLevelTemplateArgumentList &TemplateArgs) {
+ assert(PatternDecl->isThisDeclarationADefinition() &&
+ "don't have a definition to instantiate from");
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
@@ -4016,6 +4034,9 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
// Update the type of this variable template specialization.
VarSpec->setType(DI->getType());
+ // Convert the declaration into a definition now.
+ VarSpec->setCompleteDefinition();
+
// Instantiate the initializer.
InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs);
@@ -4063,7 +4084,8 @@ void Sema::BuildVariableInstantiation(
*this, NewVar->getDeclName(), NewVar->getLocation(),
NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
- Sema::ForRedeclaration);
+ NewVar->isLocalExternDecl() ? Sema::ForExternalRedeclaration
+ : forRedeclarationInCurContext());
if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl() &&
(!OldVar->getPreviousDecl()->getDeclContext()->isDependentContext() ||
@@ -4120,6 +4142,9 @@ void Sema::BuildVariableInstantiation(
void Sema::InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (ASTMutationListener *L = getASTContext().getASTMutationListener())
+ L->VariableDefinitionInstantiated(Var);
+
// We propagate the 'inline' flag with the initializer, because it
// would otherwise imply that the variable is a definition for a
// non-static data member.
@@ -4129,12 +4154,8 @@ void Sema::InstantiateVariableInitializer(
Var->setImplicitlyInline();
if (OldVar->getInit()) {
- if (Var->isStaticDataMember() && !OldVar->isOutOfLine())
- PushExpressionEvaluationContext(
- Sema::ExpressionEvaluationContext::ConstantEvaluated, OldVar);
- else
- PushExpressionEvaluationContext(
- Sema::ExpressionEvaluationContext::PotentiallyEvaluated, OldVar);
+ EnterExpressionEvaluationContext Evaluated(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
// Instantiate the initializer.
ExprResult Init;
@@ -4162,8 +4183,6 @@ void Sema::InstantiateVariableInitializer(
// because of a bogus initializer.
Var->setInvalidDecl();
}
-
- PopExpressionEvaluationContext();
} else {
if (Var->isStaticDataMember()) {
if (!Var->isOutOfLine())
@@ -4188,26 +4207,16 @@ void Sema::InstantiateVariableInitializer(
///
/// \param PointOfInstantiation the point at which the instantiation was
/// required. Note that this is not precisely a "point of instantiation"
-/// for the function, but it's close.
+/// for the variable, but it's close.
///
-/// \param Var the already-instantiated declaration of a static member
-/// variable of a class template specialization.
+/// \param Var the already-instantiated declaration of a templated variable.
///
/// \param Recursive if true, recursively instantiates any functions that
/// are required by this instantiation.
///
/// \param DefinitionRequired if true, then we are performing an explicit
-/// instantiation where an out-of-line definition of the member variable
-/// is required. Complain if there is no such definition.
-void Sema::InstantiateStaticDataMemberDefinition(
- SourceLocation PointOfInstantiation,
- VarDecl *Var,
- bool Recursive,
- bool DefinitionRequired) {
- InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive,
- DefinitionRequired);
-}
-
+/// instantiation where a definition of the variable is required. Complain
+/// if there is no such definition.
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarDecl *Var, bool Recursive,
bool DefinitionRequired, bool AtEndOfTU) {
@@ -4264,6 +4273,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// If this is a static data member template, there might be an
// uninstantiated initializer on the declaration. If so, instantiate
// it now.
+ //
+ // FIXME: This largely duplicates what we would do below. The difference
+ // is that along this path we may instantiate an initializer from an
+ // in-class declaration of the template and instantiate the definition
+ // from a separate out-of-class definition.
if (PatternDecl->isStaticDataMember() &&
(PatternDecl = PatternDecl->getFirstDecl())->hasInit() &&
!Var->hasInit()) {
@@ -4351,10 +4365,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
return;
// C++11 [temp.explicit]p10:
- // Except for inline functions, [...] explicit instantiation declarations
+ // 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.
- if (TSK == TSK_ExplicitInstantiationDeclaration)
+ if (TSK == TSK_ExplicitInstantiationDeclaration &&
+ !Var->isUsableInConstantExpressions(getASTContext()))
return;
// Make sure to pass the instantiated variable to the consumer at the end.
@@ -4427,7 +4443,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// Merge the definition with the declaration.
LookupResult R(*this, Var->getDeclName(), Var->getLocation(),
- LookupOrdinaryName, ForRedeclaration);
+ LookupOrdinaryName, forRedeclarationInCurContext());
R.addDecl(OldVar);
MergeVarDecl(Var, R);
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 9f572007d8a7..d81837dad508 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -26,6 +26,19 @@ using namespace clang;
// Visitor that collects unexpanded parameter packs
//----------------------------------------------------------------------------
+/// \brief Retrieve the depth and index of a parameter pack.
+static std::pair<unsigned, unsigned>
+getDepthAndIndex(NamedDecl *ND) {
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
+ return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
+
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+}
+
namespace {
/// \brief A class that collects unexpanded parameter packs.
class CollectUnexpandedParameterPacksVisitor :
@@ -36,15 +49,36 @@ namespace {
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
- bool InLambda;
-
+ bool InLambda = false;
+ unsigned DepthLimit = (unsigned)-1;
+
+ void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
+ if (auto *PVD = dyn_cast<ParmVarDecl>(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 *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
+ if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
+ return;
+ } else if (getDepthAndIndex(ND).first >= DepthLimit)
+ return;
+
+ Unexpanded.push_back({ND, Loc});
+ }
+ void addUnexpanded(const TemplateTypeParmType *T,
+ SourceLocation Loc = SourceLocation()) {
+ if (T->getDepth() < DepthLimit)
+ Unexpanded.push_back({T, Loc});
+ }
+
public:
explicit CollectUnexpandedParameterPacksVisitor(
- SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
- : Unexpanded(Unexpanded), InLambda(false) { }
+ SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
+ : Unexpanded(Unexpanded) {}
bool shouldWalkTypesOfTypeLocs() const { return false; }
-
+
//------------------------------------------------------------------------
// Recording occurrences of (unexpanded) parameter packs.
//------------------------------------------------------------------------
@@ -52,7 +86,7 @@ namespace {
/// \brief Record occurrences of template type parameter packs.
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
if (TL.getTypePtr()->isParameterPack())
- Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc()));
+ addUnexpanded(TL.getTypePtr(), TL.getNameLoc());
return true;
}
@@ -63,7 +97,7 @@ namespace {
/// Ideally, this routine would never be used.
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
if (T->isParameterPack())
- Unexpanded.push_back(std::make_pair(T, SourceLocation()));
+ addUnexpanded(T);
return true;
}
@@ -72,18 +106,18 @@ namespace {
/// parameter packs in an expression.
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (E->getDecl()->isParameterPack())
- Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
+ addUnexpanded(E->getDecl(), E->getLocation());
return true;
}
/// \brief Record occurrences of template template parameter packs.
bool TraverseTemplateName(TemplateName Template) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Template.getAsTemplateDecl()))
+ if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Template.getAsTemplateDecl())) {
if (TTP->isParameterPack())
- Unexpanded.push_back(std::make_pair(TTP, SourceLocation()));
+ addUnexpanded(TTP);
+ }
return inherited::TraverseTemplateName(Template);
}
@@ -127,7 +161,7 @@ namespace {
return true;
}
- /// \brief Suppress traversel into types with location information
+ /// \brief Suppress traversal into types with location information
/// that do not contain unexpanded parameter packs.
bool TraverseTypeLoc(TypeLoc TL) {
if ((!TL.getType().isNull() &&
@@ -138,13 +172,48 @@ namespace {
return true;
}
- /// \brief Suppress traversal of non-parameter declarations, since
- /// they cannot contain unexpanded parameter packs.
+ /// \brief Suppress traversal of parameter packs.
bool TraverseDecl(Decl *D) {
- if ((D && isa<ParmVarDecl>(D)) || InLambda)
- return inherited::TraverseDecl(D);
+ // A function parameter pack is a pack expansion, so cannot contain
+ // an unexpanded parameter pack. Likewise for a template parameter
+ // pack that contains any references to other packs.
+ if (D->isParameterPack())
+ return true;
- return true;
+ return inherited::TraverseDecl(D);
+ }
+
+ /// \brief Suppress traversal of pack-expanded attributes.
+ bool TraverseAttr(Attr *A) {
+ if (A->isPackExpansion())
+ return true;
+
+ return inherited::TraverseAttr(A);
+ }
+
+ /// \brief Suppress traversal of pack expansion expressions and types.
+ ///@{
+ bool TraversePackExpansionType(PackExpansionType *T) { return true; }
+ bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; }
+ bool TraversePackExpansionExpr(PackExpansionExpr *E) { return true; }
+ bool TraverseCXXFoldExpr(CXXFoldExpr *E) { return true; }
+
+ ///@}
+
+ /// \brief Suppress traversal of using-declaration pack expansion.
+ bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ if (D->isPackExpansion())
+ return true;
+
+ return inherited::TraverseUnresolvedUsingValueDecl(D);
+ }
+
+ /// \brief Suppress traversal of using-declaration pack expansion.
+ bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ if (D->isPackExpansion())
+ return true;
+
+ return inherited::TraverseUnresolvedUsingTypenameDecl(D);
}
/// \brief Suppress traversal of template argument pack expansions.
@@ -163,6 +232,22 @@ namespace {
return inherited::TraverseTemplateArgumentLoc(ArgLoc);
}
+ /// \brief Suppress traversal of base specifier pack expansions.
+ bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) {
+ if (Base.isPackExpansion())
+ return true;
+
+ return inherited::TraverseCXXBaseSpecifier(Base);
+ }
+
+ /// \brief Suppress traversal of mem-initializer pack expansions.
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
+ if (Init->isPackExpansion())
+ return true;
+
+ return inherited::TraverseConstructorInitializer(Init);
+ }
+
/// \brief Note whether we're traversing a lambda containing an unexpanded
/// parameter pack. In this case, the unexpanded pack can occur anywhere,
/// including all the places where we normally wouldn't look. Within a
@@ -175,25 +260,27 @@ namespace {
return true;
bool WasInLambda = InLambda;
- InLambda = true;
+ unsigned OldDepthLimit = DepthLimit;
- // If any capture names a function parameter pack, that pack is expanded
- // when the lambda is expanded.
- for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
- E = Lambda->capture_end();
- I != E; ++I) {
- if (I->capturesVariable()) {
- VarDecl *VD = I->getCapturedVar();
- if (VD->isParameterPack())
- Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
- }
- }
+ InLambda = true;
+ if (auto *TPL = Lambda->getTemplateParameterList())
+ DepthLimit = TPL->getDepth();
inherited::TraverseLambdaExpr(Lambda);
InLambda = WasInLambda;
+ DepthLimit = OldDepthLimit;
return true;
}
+
+ /// Suppress traversal within pack expansions in lambda captures.
+ bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
+ Expr *Init) {
+ if (C->isPackExpansion())
+ return true;
+
+ return inherited::TraverseLambdaCapture(Lambda, C, Init);
+ }
};
}
@@ -220,13 +307,33 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
if (Unexpanded.empty())
return false;
- // If we are within a lambda expression, that lambda contains an unexpanded
+ // If we are within a lambda expression and referencing a pack that is not
+ // a parameter of the lambda itself, that lambda contains an unexpanded
// parameter pack, and we are done.
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
// later.
+ SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
for (unsigned N = FunctionScopes.size(); N; --N) {
if (sema::LambdaScopeInfo *LSI =
dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
+ 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);
+ }
+ }
+
+ // If we have references to a parameter pack of the innermost enclosing
+ // lambda, only diagnose those ones. We don't know whether any other
+ // unexpanded parameters referenced herein are actually unexpanded;
+ // they might be expanded at an outer level.
+ if (!LambdaParamPackReferences.empty()) {
+ Unexpanded = LambdaParamPackReferences;
+ break;
+ }
+
LSI->ContainsUnexpandedParameterPack = true;
return false;
}
@@ -520,19 +627,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions);
}
-/// \brief Retrieve the depth and index of a parameter pack.
-static std::pair<unsigned, unsigned>
-getDepthAndIndex(NamedDecl *ND) {
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
- return std::make_pair(TTP->getDepth(), TTP->getIndex());
-
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
- return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
-
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
- return std::make_pair(TTP->getDepth(), TTP->getIndex());
-}
-
bool Sema::CheckParameterPacksForExpansion(
SourceLocation EllipsisLoc, SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
@@ -725,6 +819,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_half:
case TST_float:
case TST_double:
+ case TST_Float16:
case TST_float128:
case TST_bool:
case TST_decimal32:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 598a11300b87..2fffe8e17970 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1392,8 +1392,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
else
Result = Context.Int128Ty;
break;
- case DeclSpec::TST_half: Result = Context.HalfTy; break;
- case DeclSpec::TST_float: Result = Context.FloatTy; break;
+ case DeclSpec::TST_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:
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
Result = Context.LongDoubleTy;
@@ -2179,9 +2180,18 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(Loc, diag::err_opencl_vla);
return QualType();
}
- // CUDA device code doesn't support VLAs.
- if (getLangOpts().CUDA && T->isVariableArrayType())
- CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget();
+
+ if (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();
+ }
+ }
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOpts().C99) {
@@ -2834,8 +2844,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::TemplateParamContext:
if (isa<DeducedTemplateSpecializationType>(Deduced))
Error = 19; // Template parameter
- else if (!SemaRef.getLangOpts().CPlusPlus1z)
- Error = 8; // Template parameter (until C++1z)
+ else if (!SemaRef.getLangOpts().CPlusPlus17)
+ Error = 8; // Template parameter (until C++17)
break;
case Declarator::BlockLiteralContext:
Error = 9; // Block literal
@@ -3064,6 +3074,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
S.Diag(D.getCommaLoc(), diag::note_empty_parens_function_call)
<< FixItHint::CreateReplacement(D.getCommaLoc(), ";")
<< D.getIdentifier();
+ Result.suppressDiagnostics();
}
}
@@ -3105,6 +3116,99 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
}
}
+/// Produce an appropriate diagnostic for a declarator with top-level
+/// parentheses.
+static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) {
+ DeclaratorChunk &Paren = D.getTypeObject(D.getNumTypeObjects() - 1);
+ assert(Paren.Kind == DeclaratorChunk::Paren &&
+ "do not have redundant top-level parentheses");
+
+ // This is a syntactic check; we're not interested in cases that arise
+ // during template instantiation.
+ if (S.inTemplateInstantiation())
+ return;
+
+ // Check whether this could be intended to be a construction of a temporary
+ // object in C++ via a function-style cast.
+ bool CouldBeTemporaryObject =
+ S.getLangOpts().CPlusPlus && D.isExpressionContext() &&
+ !D.isInvalidType() && D.getIdentifier() &&
+ D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier &&
+ (T->isRecordType() || T->isDependentType()) &&
+ D.getDeclSpec().getTypeQualifiers() == 0 && D.isFirstDeclarator();
+
+ for (auto &C : D.type_objects()) {
+ switch (C.Kind) {
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Paren:
+ continue;
+
+ case DeclaratorChunk::Array:
+ if (!C.Arr.NumElts)
+ CouldBeTemporaryObject = false;
+ continue;
+
+ case DeclaratorChunk::Reference:
+ // FIXME: Suppress the warning here if there is no initializer; we're
+ // going to give an error anyway.
+ // We assume that something like 'T (&x) = y;' is highly likely to not
+ // be intended to be a temporary object.
+ CouldBeTemporaryObject = false;
+ continue;
+
+ case DeclaratorChunk::Function:
+ // In a new-type-id, function chunks require parentheses.
+ if (D.getContext() == Declarator::CXXNewContext)
+ return;
+ LLVM_FALLTHROUGH;
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
+ // These cannot appear in expressions.
+ CouldBeTemporaryObject = false;
+ continue;
+ }
+ }
+
+ // FIXME: If there is an initializer, assume that this is not intended to be
+ // a construction of a temporary object.
+
+ // Check whether the name has already been declared; if not, this is not a
+ // function-style cast.
+ if (CouldBeTemporaryObject) {
+ LookupResult Result(S, D.getIdentifier(), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (!S.LookupName(Result, S.getCurScope()))
+ CouldBeTemporaryObject = false;
+ Result.suppressDiagnostics();
+ }
+
+ SourceRange ParenRange(Paren.Loc, Paren.EndLoc);
+
+ if (!CouldBeTemporaryObject) {
+ S.Diag(Paren.Loc, diag::warn_redundant_parens_around_declarator)
+ << ParenRange << FixItHint::CreateRemoval(Paren.Loc)
+ << FixItHint::CreateRemoval(Paren.EndLoc);
+ return;
+ }
+
+ S.Diag(Paren.Loc, diag::warn_parens_disambiguated_as_variable_declaration)
+ << ParenRange << D.getIdentifier();
+ auto *RD = T->getAsCXXRecordDecl();
+ if (!RD || !RD->hasDefinition() || RD->hasNonTrivialDestructor())
+ S.Diag(Paren.Loc, diag::note_raii_guard_add_name)
+ << FixItHint::CreateInsertion(Paren.Loc, " varname") << T
+ << D.getIdentifier();
+ // FIXME: A cast to void is probably a better suggestion in cases where it's
+ // valid (when there is no initializer and we're not in a condition).
+ S.Diag(D.getLocStart(), diag::note_function_style_cast_add_parentheses)
+ << FixItHint::CreateInsertion(D.getLocStart(), "(")
+ << FixItHint::CreateInsertion(S.getLocForEndOfToken(D.getLocEnd()), ")");
+ S.Diag(Paren.Loc, diag::note_remove_parens_for_variable_declaration)
+ << FixItHint::CreateRemoval(Paren.Loc)
+ << FixItHint::CreateRemoval(Paren.EndLoc);
+}
+
/// Helper for figuring out the default CC for a function declarator type. If
/// this is the outermost chunk, then we can determine the CC from the
/// declarator context. If not, then this could be either a member function
@@ -3387,13 +3491,20 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator,
isCFError = (S.CFError == recordDecl);
} else {
// Check whether this is CFError, which we identify based on its bridge
- // to NSError.
+ // to NSError. CFErrorRef used to be declared with "objc_bridge" but is
+ // now declared with "objc_bridge_mutable", so look for either one of
+ // the two attributes.
if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) {
- if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) {
- if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) {
- S.CFError = recordDecl;
- isCFError = true;
- }
+ IdentifierInfo *bridgedType = nullptr;
+ if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>())
+ bridgedType = bridgeAttr->getBridgedType();
+ else if (auto bridgeAttr =
+ recordDecl->getAttr<ObjCBridgeMutableAttr>())
+ bridgedType = bridgeAttr->getBridgedType();
+
+ if (bridgedType == S.getNSErrorIdent()) {
+ S.CFError = recordDecl;
+ isCFError = true;
}
}
}
@@ -3499,7 +3610,8 @@ static void fixItNullability(Sema &S, DiagnosticBuilder &Diag,
static void emitNullabilityConsistencyWarning(Sema &S,
SimplePointerKind PointerKind,
- SourceLocation PointerLoc) {
+ SourceLocation PointerLoc,
+ SourceLocation PointerEndLoc) {
assert(PointerLoc.isValid());
if (PointerKind == SimplePointerKind::Array) {
@@ -3509,14 +3621,15 @@ static void emitNullabilityConsistencyWarning(Sema &S,
<< static_cast<unsigned>(PointerKind);
}
- if (PointerLoc.isMacroID())
+ auto FixItLoc = PointerEndLoc.isValid() ? PointerEndLoc : PointerLoc;
+ if (FixItLoc.isMacroID())
return;
auto addFixIt = [&](NullabilityKind Nullability) {
- auto Diag = S.Diag(PointerLoc, diag::note_nullability_fix_it);
+ auto Diag = S.Diag(FixItLoc, diag::note_nullability_fix_it);
Diag << static_cast<unsigned>(Nullability);
Diag << static_cast<unsigned>(PointerKind);
- fixItNullability(S, Diag, PointerLoc, Nullability);
+ fixItNullability(S, Diag, FixItLoc, Nullability);
};
addFixIt(NullabilityKind::Nullable);
addFixIt(NullabilityKind::NonNull);
@@ -3528,9 +3641,10 @@ static void emitNullabilityConsistencyWarning(Sema &S,
///
/// If the file has \e not seen other uses of nullability, this particular
/// pointer is saved for possible later diagnosis. See recordNullabilitySeen().
-static void checkNullabilityConsistency(Sema &S,
- SimplePointerKind pointerKind,
- SourceLocation pointerLoc) {
+static void
+checkNullabilityConsistency(Sema &S, SimplePointerKind pointerKind,
+ SourceLocation pointerLoc,
+ SourceLocation pointerEndLoc = SourceLocation()) {
// Determine which file we're performing consistency checking for.
FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc);
if (file.isInvalid())
@@ -3551,6 +3665,7 @@ static void checkNullabilityConsistency(Sema &S,
if (fileNullability.PointerLoc.isInvalid() &&
!S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) {
fileNullability.PointerLoc = pointerLoc;
+ fileNullability.PointerEndLoc = pointerEndLoc;
fileNullability.PointerKind = static_cast<unsigned>(pointerKind);
}
@@ -3558,7 +3673,7 @@ static void checkNullabilityConsistency(Sema &S,
}
// Complain about missing nullability.
- emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc);
+ emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc, pointerEndLoc);
}
/// Marks that a nullability feature has been used in the file containing
@@ -3584,7 +3699,8 @@ static void recordNullabilitySeen(Sema &S, SourceLocation loc) {
return;
auto kind = static_cast<SimplePointerKind>(fileNullability.PointerKind);
- emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc);
+ emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc,
+ fileNullability.PointerEndLoc);
}
/// Returns true if any of the declarator chunks before \p endIndex include a
@@ -3894,6 +4010,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Returns true if _Nonnull was inferred.
auto inferPointerNullability = [&](SimplePointerKind pointerKind,
SourceLocation pointerLoc,
+ SourceLocation pointerEndLoc,
AttributeList *&attrs) -> AttributeList * {
// We've seen a pointer.
if (NumPointersRemaining > 0)
@@ -3949,7 +4066,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Fallthrough.
case CAMN_Yes:
- checkNullabilityConsistency(S, pointerKind, pointerLoc);
+ checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc);
}
return nullptr;
};
@@ -3972,6 +4089,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (auto *attr = inferPointerNullability(
pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
+ D.getDeclSpec().getLocEnd(),
D.getMutableDeclSpec().getAttributes().getListRef())) {
T = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*inferNullability),T,T);
@@ -3999,6 +4117,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren;
switch (DeclType.Kind) {
case DeclaratorChunk::Paren:
+ if (i == 0)
+ warnAboutRedundantParens(S, D, T);
T = S.BuildParenType(T);
break;
case DeclaratorChunk::BlockPointer:
@@ -4007,8 +4127,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(DeclType.Loc, diag::err_blocks_disable) << LangOpts.OpenCL;
// Handle pointer nullability.
- inferPointerNullability(SimplePointerKind::BlockPointer,
- DeclType.Loc, DeclType.getAttrListRef());
+ inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc,
+ DeclType.EndLoc, DeclType.getAttrListRef());
T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) {
@@ -4030,7 +4150,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Handle pointer nullability
inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc,
- DeclType.getAttrListRef());
+ DeclType.EndLoc, DeclType.getAttrListRef());
if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) {
T = Context.getObjCObjectPointerType(T);
@@ -4175,7 +4295,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getSourceRange();
D.setInvalidType(true);
} else if (D.getName().getKind() ==
- UnqualifiedId::IK_DeductionGuideName) {
+ UnqualifiedId::IK_DeductionGuideName) {
if (T != Context.DependentTy) {
S.Diag(D.getDeclSpec().getLocStart(),
diag::err_deduction_guide_with_complex_decl)
@@ -4343,7 +4463,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Exception specs are not allowed in typedefs. Complain, but add it
// anyway.
- if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus1z)
+ if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus17)
S.Diag(FTI.getExceptionSpecLocBeg(),
diag::err_exception_spec_in_typedef)
<< (D.getContext() == Declarator::AliasDeclContext ||
@@ -4356,7 +4476,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
- if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
+ if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus
+ && !LangOpts.OpenCL) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T, EI);
} else {
@@ -4478,6 +4599,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
HasAnyInterestingExtParameterInfos = true;
}
+ if (Param->hasAttr<NoEscapeAttr>()) {
+ ExtParameterInfos[i] = ExtParameterInfos[i].withIsNoEscape(true);
+ HasAnyInterestingExtParameterInfos = true;
+ }
+
ParamTys.push_back(ParamTy);
}
@@ -4524,8 +4650,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType ClsType;
// Handle pointer nullability.
- inferPointerNullability(SimplePointerKind::MemberPointer,
- DeclType.Loc, DeclType.getAttrListRef());
+ inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc,
+ DeclType.EndLoc, DeclType.getAttrListRef());
if (SS.isInvalid()) {
// Avoid emitting extra errors if we already errored on the scope.
@@ -4828,7 +4954,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
-
if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount)
inferARCWriteback(state, T);
@@ -5378,6 +5503,18 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
ATL.setParensRange(SourceRange());
}
+static void fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL,
+ const AttributeList *Attrs) {
+ while (Attrs && Attrs->getKind() != AttributeList::AT_AddressSpace)
+ Attrs = Attrs->getNext();
+
+ assert(Attrs && "no address_space attribute found at the expected location!");
+
+ DASTL.setAttrNameLoc(Attrs->getLoc());
+ DASTL.setAttrExprOperand(Attrs->getArgAsExpr(0));
+ DASTL.setAttrOperandParensRange(SourceRange());
+}
+
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
@@ -5400,6 +5537,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+
+ if (DependentAddressSpaceTypeLoc DASTL =
+ CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
+ fillDependentAddressSpaceTypeLoc(DASTL, D.getTypeObject(i).getAttrs());
+ CurrTL = DASTL.getPointeeTypeLoc().getUnqualifiedLoc();
+ }
+
// An AtomicTypeLoc might be produced by an atomic qualifier in this
// declarator chunk.
if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) {
@@ -5492,16 +5636,77 @@ 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) {
+ if (!AddrSpace->isValueDependent()) {
+
+ // If this type is already address space qualified, 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) {
+ Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers);
+ return QualType();
+ }
+
+ llvm::APSInt addrSpace(32);
+ if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) {
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << "'address_space'" << AANT_ArgumentIntegerConstant
+ << AddrSpace->getSourceRange();
+ return QualType();
+ }
+
+ // Bounds checking.
+ if (addrSpace.isSigned()) {
+ if (addrSpace.isNegative()) {
+ Diag(AttrLoc, diag::err_attribute_address_space_negative)
+ << AddrSpace->getSourceRange();
+ return QualType();
+ }
+ addrSpace.setIsSigned(false);
+ }
+
+ llvm::APSInt max(addrSpace.getBitWidth());
+ max =
+ Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace;
+ if (addrSpace > max) {
+ Diag(AttrLoc, diag::err_attribute_address_space_too_high)
+ << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange();
+ return QualType();
+ }
+
+ LangAS ASIdx =
+ getLangASFromTargetAS(static_cast<unsigned>(addrSpace.getZExtValue()));
+
+ return Context.getAddrSpaceQualType(T, ASIdx);
+ }
+
+ // A check with similar intentions as checking if a type already has an
+ // address space except for on a dependent types, basically if the
+ // current type is already a DependentAddressSpaceType then its already
+ // lined up to have another address space on it and we can't have
+ // multiple address spaces on the one pointer indirection
+ if (T->getAs<DependentAddressSpaceType>()) {
+ Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers);
+ return QualType();
+ }
+
+ return Context.getDependentAddressSpaceType(T, 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.
static void HandleAddressSpaceTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S){
-
// If this type is already address space qualified, 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()) {
+ if (Type.getAddressSpace() != LangAS::Default) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
Attr.setInvalid();
return;
@@ -5515,46 +5720,43 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
return;
}
- unsigned ASIdx;
+ LangAS ASIdx;
if (Attr.getKind() == AttributeList::AT_AddressSpace) {
+
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 1;
- Attr.setInvalid();
- return;
- }
- Expr *ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
- llvm::APSInt addrSpace(32);
- if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() ||
- !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << ASArgExpr->getSourceRange();
+ << Attr.getName() << 1;
Attr.setInvalid();
return;
}
- // Bounds checking.
- if (addrSpace.isSigned()) {
- if (addrSpace.isNegative()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
- << ASArgExpr->getSourceRange();
- Attr.setInvalid();
+ Expr *ASArgExpr;
+ if (Attr.isArgIdent(0)) {
+ // Special case where the argument is a template id.
+ CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
+
+ ExprResult AddrSpace = S.ActOnIdExpression(
+ S.getCurScope(), SS, TemplateKWLoc, id, false, false);
+ if (AddrSpace.isInvalid())
return;
- }
- addrSpace.setIsSigned(false);
+
+ ASArgExpr = static_cast<Expr *>(AddrSpace.get());
+ } else {
+ ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
}
- llvm::APSInt max(addrSpace.getBitWidth());
- max = Qualifiers::MaxAddressSpace - LangAS::FirstTargetAddressSpace;
- if (addrSpace > max) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
- << (unsigned)max.getZExtValue() << ASArgExpr->getSourceRange();
+
+ // Create the DependentAddressSpaceType or append an address space onto
+ // the type.
+ QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc());
+
+ if (!T.isNull())
+ Type = T;
+ else
Attr.setInvalid();
- return;
- }
- ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()) +
- LangAS::FirstTargetAddressSpace;
} else {
// The keyword-based type attributes imply which address space to use.
switch (Attr.getKind()) {
@@ -5566,13 +5768,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
ASIdx = LangAS::opencl_constant; break;
case AttributeList::AT_OpenCLGenericAddressSpace:
ASIdx = LangAS::opencl_generic; break;
+ case AttributeList::AT_OpenCLPrivateAddressSpace:
+ ASIdx = LangAS::opencl_private; break;
default:
- assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace);
- ASIdx = 0; break;
+ llvm_unreachable("Invalid address space");
}
+
+ Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
-
- Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
/// Does this type have a "direct" ownership qualifier? That is,
@@ -6800,6 +7003,92 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr,
}
}
+static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
+ QualType &T, TypeAttrLocation TAL) {
+ Declarator &D = State.getDeclarator();
+
+ // Handle the cases where address space should not be deduced.
+ //
+ // The pointee type of a pointer type is alwasy deduced since a pointer always
+ // points to some memory location which should has an address space.
+ //
+ // There are situations that at the point of certain declarations, the address
+ // space may be unknown and better to be left as default. For example, when
+ // definining a typedef or struct type, they are not associated with any
+ // specific address space. Later on, they may be used with any address space
+ // to declare a variable.
+ //
+ // The return value of a function is r-value, therefore should not have
+ // address space.
+ //
+ // The void type does not occupy memory, therefore should not have address
+ // space, except when it is used as a pointee type.
+ //
+ // Since LLVM assumes function type is in default address space, it should not
+ // have address space.
+ auto ChunkIndex = State.getCurrentChunkIndex();
+ bool IsPointee =
+ ChunkIndex > 0 &&
+ (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
+ bool IsFuncReturnType =
+ ChunkIndex > 0 &&
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
+ bool IsFuncType =
+ ChunkIndex < D.getNumTypeObjects() &&
+ D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function;
+ if ( // Do not deduce addr space for function return type and function type,
+ // 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() == Declarator::MemberContext && !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.
+ (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef &&
+ !IsPointee) ||
+ // Do not deduce addr space of the void type, e.g. in f(void), otherwise
+ // it will fail some sema check.
+ (T->isVoidType() && !IsPointee))
+ return;
+
+ LangAS ImpAddr;
+ // Put OpenCL automatic variable in private address space.
+ // OpenCL v1.2 s6.5:
+ // The default address space name for arguments to a function in a
+ // program, or local variables of a function is __private. All function
+ // arguments shall be in the __private address space.
+ if (State.getSema().getLangOpts().OpenCLVersion <= 120) {
+ ImpAddr = LangAS::opencl_private;
+ } else {
+ // If address space is not set, OpenCL 2.0 defines non private default
+ // address spaces for some cases:
+ // OpenCL 2.0, section 6.5:
+ // The address space for a variable at program scope or a static variable
+ // inside a function can either be __global or __constant, but defaults to
+ // __global if not specified.
+ // (...)
+ // Pointers that are declared without pointing to a named address space
+ // point to the generic address space.
+ if (IsPointee) {
+ ImpAddr = LangAS::opencl_generic;
+ } else {
+ if (D.getContext() == Declarator::FileContext) {
+ ImpAddr = LangAS::opencl_global;
+ } else {
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) {
+ ImpAddr = LangAS::opencl_global;
+ } else {
+ ImpAddr = LangAS::opencl_private;
+ }
+ }
+ }
+ }
+ T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
+}
+
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL, AttributeList *attrs) {
// Scan through and apply attributes to this type where it makes sense. Some
@@ -6807,7 +7096,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// type, but others can be present in the type specifiers even though they
// apply to the decl. Here we apply type attributes and ignore the rest.
- bool hasOpenCLAddressSpace = false;
while (attrs) {
AttributeList &attr = *attrs;
attrs = attr.getNext(); // reset to the next here due to early loop continue
@@ -6870,7 +7158,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
- hasOpenCLAddressSpace = true;
break;
OBJC_POINTER_TYPE_ATTRS_CASELIST:
if (!handleObjCPointerTypeAttr(state, attr, type))
@@ -6971,70 +7258,40 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
}
}
- // If address space is not set, OpenCL 2.0 defines non private default
- // address spaces for some cases:
- // OpenCL 2.0, section 6.5:
- // The address space for a variable at program scope or a static variable
- // inside a function can either be __global or __constant, but defaults to
- // __global if not specified.
- // (...)
- // Pointers that are declared without pointing to a named address space point
- // to the generic address space.
- if (state.getSema().getLangOpts().OpenCLVersion >= 200 &&
- !hasOpenCLAddressSpace && type.getAddressSpace() == 0 &&
- (TAL == TAL_DeclSpec || TAL == TAL_DeclChunk)) {
- Declarator &D = state.getDeclarator();
- if (state.getCurrentChunkIndex() > 0 &&
- (D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
- DeclaratorChunk::Pointer ||
- D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
- DeclaratorChunk::BlockPointer)) {
- type = state.getSema().Context.getAddrSpaceQualType(
- type, LangAS::opencl_generic);
- } else if (state.getCurrentChunkIndex() == 0 &&
- D.getContext() == Declarator::FileContext &&
- !D.isFunctionDeclarator() && !D.isFunctionDefinition() &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
- !type->isSamplerT())
- type = state.getSema().Context.getAddrSpaceQualType(
- type, LangAS::opencl_global);
- else if (state.getCurrentChunkIndex() == 0 &&
- D.getContext() == Declarator::BlockContext &&
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
- type = state.getSema().Context.getAddrSpaceQualType(
- type, LangAS::opencl_global);
- }
+ if (!state.getSema().getLangOpts().OpenCL ||
+ type.getAddressSpace() != LangAS::Default)
+ return;
+
+ deduceOpenCLImplicitAddrSpace(state, type, TAL);
}
void Sema::completeExprArrayBound(Expr *E) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) {
- SourceLocation PointOfInstantiation = E->getExprLoc();
-
- if (MemberSpecializationInfo *MSInfo =
- Var->getMemberSpecializationInfo()) {
- // If we don't already have a point of instantiation, this is it.
- if (MSInfo->getPointOfInstantiation().isInvalid()) {
- MSInfo->setPointOfInstantiation(PointOfInstantiation);
-
- // This is a modification of an existing AST node. Notify
- // listeners.
- if (ASTMutationListener *L = getASTMutationListener())
- L->StaticDataMemberInstantiated(Var);
+ auto *Def = Var->getDefinition();
+ if (!Def) {
+ SourceLocation PointOfInstantiation = E->getExprLoc();
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
+ Def = Var->getDefinition();
+
+ // If we don't already have a point of instantiation, and we managed
+ // to instantiate a definition, this is the point of instantiation.
+ // Otherwise, we don't request an end-of-TU instantiation, so this is
+ // not a point of instantiation.
+ // FIXME: Is this really the right behavior?
+ if (Var->getPointOfInstantiation().isInvalid() && Def) {
+ assert(Var->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation &&
+ "explicit instantiation with no point of instantiation");
+ Var->setTemplateSpecializationKind(
+ Var->getTemplateSpecializationKind(), PointOfInstantiation);
}
- } else {
- VarTemplateSpecializationDecl *VarSpec =
- cast<VarTemplateSpecializationDecl>(Var);
- if (VarSpec->getPointOfInstantiation().isInvalid())
- VarSpec->setPointOfInstantiation(PointOfInstantiation);
}
- InstantiateVariableDefinition(PointOfInstantiation, Var);
-
- // Update the type to the newly instantiated definition's type both
- // here and within the expression.
- if (VarDecl *Def = Var->getDefinition()) {
+ // Update the type to the definition's type both here and within the
+ // expression.
+ if (Def) {
DRE->setDecl(Def);
QualType T = Def->getType();
DRE->setType(T);
@@ -7303,11 +7560,15 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// Give the external AST source a chance to complete the type.
if (auto *Source = Context.getExternalSource()) {
- if (Tag)
- Source->CompleteType(Tag->getDecl());
- else
- Source->CompleteType(IFace->getDecl());
-
+ if (Tag) {
+ TagDecl *TagD = Tag->getDecl();
+ if (TagD->hasExternalLexicalStorage())
+ Source->CompleteType(TagD);
+ } else {
+ ObjCInterfaceDecl *IFaceD = IFace->getDecl();
+ if (IFaceD->hasExternalLexicalStorage())
+ Source->CompleteType(IFace->getDecl());
+ }
// If the external source completed the type, go through the motions
// again to ensure we're allowed to use the completed type.
if (!T->isIncompleteType())
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 91da9f88c59b..96969ea87a13 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -835,6 +835,18 @@ public:
Expr *SizeExpr,
SourceLocation AttributeLoc);
+ /// \brief Build a new DependentAddressSpaceType or return the pointee
+ /// type variable with the correct address space (retrieved from
+ /// AddrSpaceExpr) applied to it. The former will be returned in cases
+ /// where the address space remains dependent.
+ ///
+ /// By default, performs semantic analysis when building the type with address
+ /// space applied. Subclasses may override this routine to provide different
+ /// behavior.
+ QualType RebuildDependentAddressSpaceType(QualType PointeeType,
+ Expr *AddrSpaceExpr,
+ SourceLocation AttributeLoc);
+
/// \brief Build a new function type.
///
/// By default, performs semantic analysis when building the function type.
@@ -1666,6 +1678,22 @@ public:
ReductionId, UnresolvedReductions);
}
+ /// Build a new OpenMP 'in_reduction' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *
+ RebuildOMPInReductionClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ return getSema().ActOnOpenMPInReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
+ ReductionId, UnresolvedReductions);
+ }
+
/// \brief Build a new OpenMP 'linear' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -4171,7 +4199,6 @@ TreeTransform<Derived>::TransformTypeWithDeducedTST(TypeSourceInfo *DI) {
TypeLoc TL = DI->getTypeLoc();
TLB.reserve(TL.getFullDataSize());
- Qualifiers Quals;
auto QTL = TL.getAs<QualifiedTypeLoc>();
if (QTL)
TL = QTL.getUnqualifiedLoc();
@@ -4769,7 +4796,53 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
return Result;
}
-template<typename Derived>
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformDependentAddressSpaceType(
+ TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) {
+ const DependentAddressSpaceType *T = TL.getTypePtr();
+
+ QualType pointeeType = getDerived().TransformType(T->getPointeeType());
+
+ if (pointeeType.isNull())
+ return QualType();
+
+ // Address spaces are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ ExprResult AddrSpace = getDerived().TransformExpr(T->getAddrSpaceExpr());
+ AddrSpace = SemaRef.ActOnConstantExpression(AddrSpace);
+ if (AddrSpace.isInvalid())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || pointeeType != T->getPointeeType() ||
+ AddrSpace.get() != T->getAddrSpaceExpr()) {
+ Result = getDerived().RebuildDependentAddressSpaceType(
+ pointeeType, AddrSpace.get(), T->getAttributeLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ // Result might be dependent or not.
+ if (isa<DependentAddressSpaceType>(Result)) {
+ DependentAddressSpaceTypeLoc NewTL =
+ TLB.push<DependentAddressSpaceTypeLoc>(Result);
+
+ NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
+ NewTL.setAttrExprOperand(TL.getAttrExprOperand());
+ NewTL.setAttrNameLoc(TL.getAttrNameLoc());
+
+ } else {
+ TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(
+ Result, getDerived().getBaseLocation());
+ TransformType(TLB, DI->getTypeLoc());
+ }
+
+ return Result;
+}
+
+template <typename Derived>
QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
VectorTypeLoc TL) {
const VectorType *T = TL.getTypePtr();
@@ -6585,8 +6658,7 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
// Rebuild the switch statement.
StmtResult Switch
- = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(),
- S->getInit(), Cond);
+ = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Init.get(), Cond);
if (Switch.isInvalid())
return StmtError();
@@ -8461,6 +8533,51 @@ OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause(
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPInReductionClause(OMPInReductionClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ CXXScopeSpec ReductionIdScopeSpec;
+ ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
+
+ DeclarationNameInfo NameInfo = C->getNameInfo();
+ if (NameInfo.getName()) {
+ NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+ if (!NameInfo.getName())
+ return nullptr;
+ }
+ // Build a list of all UDR decls with the same names ranged by the Scopes.
+ // The Scope boundary is a duplication of the previous decl.
+ llvm::SmallVector<Expr *, 16> UnresolvedReductions;
+ for (auto *E : C->reduction_ops()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
+ /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
+ } else
+ UnresolvedReductions.push_back(nullptr);
+ }
+ return getDerived().RebuildOMPInReductionClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
@@ -12253,10 +12370,18 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
IndexTypeQuals, BracketsRange);
}
-template<typename Derived>
-QualType TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
- unsigned NumElements,
- VectorType::VectorKind VecKind) {
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildDependentAddressSpaceType(
+ QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttributeLoc) {
+ return SemaRef.BuildAddressSpaceAttr(PointeeType, AddrSpaceExpr,
+ AttributeLoc);
+}
+
+template <typename Derived>
+QualType
+TreeTransform<Derived>::RebuildVectorType(QualType ElementType,
+ unsigned NumElements,
+ VectorType::VectorKind VecKind) {
// FIXME: semantic checking!
return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind);
}
@@ -12510,10 +12635,14 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Compute the transformed set of functions (and function templates) to be
// used during overload resolution.
UnresolvedSet<16> Functions;
+ bool RequiresADL;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
- assert(ULE->requiresADL());
Functions.append(ULE->decls_begin(), ULE->decls_end());
+ // If the overload could not be resolved in the template definition
+ // (because we had a dependent argument), ADL is performed as part of
+ // template instantiation.
+ RequiresADL = ULE->requiresADL();
} else {
// If we've resolved this to a particular non-member function, just call
// that function. If we resolved it to a member function,
@@ -12521,6 +12650,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl();
if (!isa<CXXMethodDecl>(ND))
Functions.addDecl(ND);
+ RequiresADL = false;
}
// Add any functions found via argument-dependent lookup.
@@ -12531,7 +12661,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (NumArgs == 1 || isPostIncDec) {
UnaryOperatorKind Opc
= UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
- return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First);
+ return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First,
+ RequiresADL);
}
if (Op == OO_Subscript) {
@@ -12555,8 +12686,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
- ExprResult Result
- = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]);
+ ExprResult Result = SemaRef.CreateOverloadedBinOp(
+ OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL);
if (Result.isInvalid())
return ExprError();