diff options
Diffstat (limited to 'lib/Sema')
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(); |