diff options
Diffstat (limited to 'lib/Sema')
52 files changed, 6620 insertions, 3023 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index c818d40c77..6c95b60003 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -1,9 +1,8 @@ //=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -250,6 +249,10 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, CFG *cfg = AC.getCFG(); if (!cfg) return; + // If the exit block is unreachable, skip processing the function. + if (cfg->getExit().pred_empty()) + return; + // Emit diagnostic if a recursive function call is detected for all paths. if (checkForRecursiveFunctionCall(FD, cfg)) S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function); @@ -995,7 +998,8 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) S.Diag(BE->getBeginLoc(), diag::warn_uninit_byref_blockvar_captured_by_block) - << VD->getDeclName(); + << VD->getDeclName() + << VD->getType().getQualifiers().hasObjCLifetime(); else DiagUninitUse(S, VD, Use, true); } @@ -1639,15 +1643,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { return ONS; } - // Helper functions - void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName, - SourceLocation Loc) { - // Gracefully handle rare cases when the analysis can't get a more - // precise source location. - if (!Loc.isValid()) - Loc = FunLocation; - PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName); - Warnings.emplace_back(std::move(Warning), getNotes()); + OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) { + return LocLocked.isValid() + ? getNotes(PartialDiagnosticAt( + LocLocked, S.PDiag(diag::note_locked_here) << Kind)) + : getNotes(); } public: @@ -1678,22 +1678,34 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc) override { - warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc); - } - - void handleIncorrectUnlockKind(StringRef Kind, Name LockName, - LockKind Expected, LockKind Received, - SourceLocation Loc) override { if (Loc.isInvalid()) Loc = FunLocation; - PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch) - << Kind << LockName << Received - << Expected); + PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock) + << Kind << LockName); Warnings.emplace_back(std::move(Warning), getNotes()); } - void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override { - warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc); + void handleIncorrectUnlockKind(StringRef Kind, Name LockName, + LockKind Expected, LockKind Received, + SourceLocation LocLocked, + SourceLocation LocUnlock) override { + if (LocUnlock.isInvalid()) + LocUnlock = FunLocation; + PartialDiagnosticAt Warning( + LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch) + << Kind << LockName << Received << Expected); + Warnings.emplace_back(std::move(Warning), + makeLockedHereNote(LocLocked, Kind)); + } + + void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked, + SourceLocation LocDoubleLock) override { + if (LocDoubleLock.isInvalid()) + LocDoubleLock = FunLocation; + PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock) + << Kind << LockName); + Warnings.emplace_back(std::move(Warning), + makeLockedHereNote(LocLocked, Kind)); } void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, @@ -1720,13 +1732,8 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind << LockName); - if (LocLocked.isValid()) { - PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here) - << Kind); - Warnings.emplace_back(std::move(Warning), getNotes(Note)); - return; - } - Warnings.emplace_back(std::move(Warning), getNotes()); + Warnings.emplace_back(std::move(Warning), + makeLockedHereNote(LocLocked, Kind)); } void handleExclusiveAndShared(StringRef Kind, Name LockName, @@ -2082,16 +2089,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Register the expressions with the CFGBuilder. for (const auto &D : fscope->PossiblyUnreachableDiags) { - if (D.stmt) - AC.registerForcedBlockExpression(D.stmt); + for (const Stmt *S : D.Stmts) + AC.registerForcedBlockExpression(S); } if (AC.getCFG()) { analyzed = true; for (const auto &D : fscope->PossiblyUnreachableDiags) { - bool processed = false; - if (D.stmt) { - const CFGBlock *block = AC.getBlockForRegisteredExpression(D.stmt); + bool AllReachable = true; + for (const Stmt *S : D.Stmts) { + const CFGBlock *block = AC.getBlockForRegisteredExpression(S); CFGReverseBlockReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis(); // FIXME: We should be able to assert that block is non-null, but @@ -2099,15 +2106,17 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // edge cases; see test/Sema/vla-2.c. if (block && cra) { // Can this block be reached from the entrance? - if (cra->isReachable(&AC.getCFG()->getEntry(), block)) - S.Diag(D.Loc, D.PD); - processed = true; + if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) { + AllReachable = false; + break; + } } + // If we cannot map to a basic block, assume the statement is + // reachable. } - if (!processed) { - // Emit the warning anyway if we cannot map to a basic block. + + if (AllReachable) S.Diag(D.Loc, D.PD); - } } } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 5f20af01fb..1684e2a1ca 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -43,6 +43,7 @@ add_clang_library(clangSema SemaInit.cpp SemaLambda.cpp SemaLookup.cpp + SemaModule.cpp SemaObjCProperty.cpp SemaOpenMP.cpp SemaOverload.cpp diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 92e65c4b81..b88ff9dd64 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -1,9 +1,8 @@ //===- CodeCompleteConsumer.cpp - Code Completion Interface ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/CoroutineStmtBuilder.h b/lib/Sema/CoroutineStmtBuilder.h index d15cf0b756..42499a32fc 100644 --- a/lib/Sema/CoroutineStmtBuilder.h +++ b/lib/Sema/CoroutineStmtBuilder.h @@ -1,9 +1,8 @@ //===- CoroutineStmtBuilder.h - Implicit coroutine stmt builder -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file defines CoroutineStmtBuilder, a class for building the implicit diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 8b002dac13..4f3e2faa8e 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -1,9 +1,8 @@ //===--- DeclSpec.cpp - Declaration Specifier Semantic Analysis -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp index a064e492c0..cb2721b920 100644 --- a/lib/Sema/DelayedDiagnostic.cpp +++ b/lib/Sema/DelayedDiagnostic.cpp @@ -1,9 +1,8 @@ //===- DelayedDiagnostic.cpp - Delayed declarator diagnostics -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index b439f72557..333f4d7098 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -1,9 +1,8 @@ //===- IdentifierResolver.cpp - Lexical Scope Name lookup -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index a7495e8e04..2234d6ba9b 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -1,9 +1,8 @@ //===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp index 50808effe0..b0aa67454a 100644 --- a/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -1,9 +1,8 @@ //===--- MultiplexExternalSemaSource.cpp ---------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/ParsedAttr.cpp b/lib/Sema/ParsedAttr.cpp index 59e5aab677..5c04443460 100644 --- a/lib/Sema/ParsedAttr.cpp +++ b/lib/Sema/ParsedAttr.cpp @@ -1,9 +1,8 @@ //======- ParsedAttr.cpp --------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp index eae5a328bf..51b0b24e57 100644 --- a/lib/Sema/Scope.cpp +++ b/lib/Sema/Scope.cpp @@ -1,9 +1,8 @@ //===- Scope.cpp - Lexical scope information --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -167,7 +166,9 @@ void Scope::dumpImpl(raw_ostream &OS) const { {SEHExceptScope, "SEHExceptScope"}, {SEHFilterScope, "SEHFilterScope"}, {CompoundStmtScope, "CompoundStmtScope"}, - {ClassInheritanceScope, "ClassInheritanceScope"}}; + {ClassInheritanceScope, "ClassInheritanceScope"}, + {CatchScope, "CatchScope"}, + }; for (auto Info : FlagInfo) { if (Flags & Info.first) { diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp index bd8db6f4ed..1003d2639c 100644 --- a/lib/Sema/ScopeInfo.cpp +++ b/lib/Sema/ScopeInfo.cpp @@ -1,9 +1,8 @@ //===--- ScopeInfo.cpp - Information about a semantic context -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 9fa3996862..7659d7cc00 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -1,9 +1,8 @@ //===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -40,6 +39,8 @@ #include "clang/Sema/TemplateInstCallback.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/Support/TimeProfiler.h" + using namespace clang; using namespace sema; @@ -93,6 +94,12 @@ public: SourceManager &SM = S->getSourceManager(); SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc)); if (IncludeLoc.isValid()) { + if (llvm::timeTraceProfilerEnabled()) { + const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc)); + llvm::timeTraceProfilerBegin( + "Source", FE != nullptr ? FE->getName() : StringRef("<unknown>")); + } + IncludeStack.push_back(IncludeLoc); S->DiagnoseNonDefaultPragmaPack( Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc); @@ -100,10 +107,14 @@ public: break; } case ExitFile: - if (!IncludeStack.empty()) + if (!IncludeStack.empty()) { + if (llvm::timeTraceProfilerEnabled()) + llvm::timeTraceProfilerEnd(); + S->DiagnoseNonDefaultPragmaPack( Sema::PragmaPackDiagnoseKind::ChangedStateAtExit, IncludeStack.pop_back_val()); + } break; default: break; @@ -256,11 +267,12 @@ void Sema::Initialize() { // Initialize predefined OpenCL types and supported extensions and (optional) // core features. if (getLangOpts().OpenCL) { - getOpenCLOptions().addSupport(Context.getTargetInfo().getSupportedOpenCLOpts()); - getOpenCLOptions().enableSupportedCore(getLangOpts().OpenCLVersion); + getOpenCLOptions().addSupport( + Context.getTargetInfo().getSupportedOpenCLOpts()); + getOpenCLOptions().enableSupportedCore(getLangOpts()); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); - if (getLangOpts().OpenCLVersion >= 200) { + if (getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) { addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); addImplicitTypedef("queue_t", Context.OCLQueueTy); addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy); @@ -837,41 +849,21 @@ void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().ModulesTS && (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface || getLangOpts().getCompilingModule() == LangOptions::CMK_None)) { + // We start in an implied global module fragment. SourceLocation StartOfTU = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); - - // We start in the global module; all those declarations are implicitly - // module-private (though they do not have module linkage). - auto &Map = PP.getHeaderSearchInfo().getModuleMap(); - auto *GlobalModule = Map.createGlobalModuleForInterfaceUnit(StartOfTU); - assert(GlobalModule && "module creation should not fail"); - - // Enter the scope of the global module. - ModuleScopes.push_back({}); - ModuleScopes.back().Module = GlobalModule; - VisibleModules.setVisible(GlobalModule, StartOfTU); - - // All declarations created from now on are owned by the global module. - auto *TU = Context.getTranslationUnitDecl(); - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); - TU->setLocalOwningModule(GlobalModule); + ActOnGlobalModuleFragmentDecl(StartOfTU); + ModuleScopes.back().ImplicitGlobalModuleFragment = true; } } -/// ActOnEndOfTranslationUnit - This is called at the very end of the -/// translation unit when EOF is reached and all but the top-level scope is -/// popped. -void Sema::ActOnEndOfTranslationUnit() { - assert(DelayedDiagnostics.getCurrentPool() == nullptr - && "reached end of translation unit with a pool attached?"); - - // If code completion is enabled, don't perform any end-of-translation-unit - // work. - if (PP.isCodeCompletionEnabled()) +void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { + // No explicit actions are required at the end of the global module fragment. + if (Kind == TUFragmentKind::Global) return; // Transfer late parsed template instantiations over to the pending template - // instantiation list. During normal compliation, the late template parser + // instantiation list. During normal compilation, the late template parser // will be installed and instantiating these templates will succeed. // // If we are building a TU prefix for serialization, it is also safe to @@ -884,46 +876,79 @@ void Sema::ActOnEndOfTranslationUnit() { LateParsedInstantiations.end()); LateParsedInstantiations.clear(); + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + DefineUsedVTables(); + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that are not required to be found. This is + // valid, but we could do better by diagnosing if an instantiation uses a + // name that was not visible at its first point of instantiation. + if (ExternalSource) { + // Load pending instantiations from the external source. + SmallVector<PendingImplicitInstantiation, 4> Pending; + ExternalSource->ReadPendingInstantiations(Pending); + for (auto PII : Pending) + if (auto Func = dyn_cast<FunctionDecl>(PII.first)) + Func->setInstantiationIsPending(true); + PendingInstantiations.insert(PendingInstantiations.begin(), + Pending.begin(), Pending.end()); + } + + { + llvm::TimeTraceScope TimeScope("PerformPendingInstantiations", + StringRef("")); + PerformPendingInstantiations(); + } + + assert(LateParsedInstantiations.empty() && + "end of TU template instantiation should not create more " + "late-parsed templates"); +} + +/// ActOnEndOfTranslationUnit - This is called at the very end of the +/// translation unit when EOF is reached and all but the top-level scope is +/// popped. +void Sema::ActOnEndOfTranslationUnit() { + assert(DelayedDiagnostics.getCurrentPool() == nullptr + && "reached end of translation unit with a pool attached?"); + + // If code completion is enabled, don't perform any end-of-translation-unit + // work. + if (PP.isCodeCompletionEnabled()) + return; + // Complete translation units and modules define vtables and perform implicit // instantiations. PCH files do not. if (TUKind != TU_Prefix) { DiagnoseUseOfUnimplementedSelectors(); - // If DefinedUsedVTables ends up marking any virtual member functions it - // might lead to more pending template instantiations, which we then need - // to instantiate. - DefineUsedVTables(); - - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully keep track of the point of instantiation (C++ [temp.point]). - // This means that name lookup that occurs within the template - // instantiation will always happen at the end of the translation unit, - // so it will find some names that are not required to be found. This is - // valid, but we could do better by diagnosing if an instantiation uses a - // name that was not visible at its first point of instantiation. - if (ExternalSource) { - // Load pending instantiations from the external source. - SmallVector<PendingImplicitInstantiation, 4> Pending; - ExternalSource->ReadPendingInstantiations(Pending); - for (auto PII : Pending) - if (auto Func = dyn_cast<FunctionDecl>(PII.first)) - Func->setInstantiationIsPending(true); - PendingInstantiations.insert(PendingInstantiations.begin(), - Pending.begin(), Pending.end()); - } - - PerformPendingInstantiations(); - - assert(LateParsedInstantiations.empty() && - "end of TU template instantiation should not create more " - "late-parsed templates"); + ActOnEndOfTranslationUnitFragment( + !ModuleScopes.empty() && ModuleScopes.back().Module->Kind == + Module::PrivateModuleFragment + ? TUFragmentKind::Private + : TUFragmentKind::Normal); if (LateTemplateParserCleanup) LateTemplateParserCleanup(OpaqueParser); CheckDelayedMemberExceptionSpecs(); + } else { + // If we are building a TU prefix for serialization, it is safe to transfer + // these over, even though they are not parsed. The end of the TU should be + // outside of any eager template instantiation scope, so when this AST is + // deserialized, these templates will not be parsed until the end of the + // combined TU. + PendingInstantiations.insert(PendingInstantiations.end(), + LateParsedInstantiations.begin(), + LateParsedInstantiations.end()); + LateParsedInstantiations.clear(); } DiagnoseUnterminatedPragmaPack(); @@ -933,7 +958,6 @@ void Sema::ActOnEndOfTranslationUnit() { // incompatible declarations. assert(DelayedOverridingExceptionSpecChecks.empty()); assert(DelayedEquivalentExceptionSpecChecks.empty()); - assert(DelayedDefaultedMemberExceptionSpecs.empty()); // All dllexport classes should have been processed already. assert(DelayedDllExportClasses.empty()); @@ -981,13 +1005,24 @@ void Sema::ActOnEndOfTranslationUnit() { checkUndefinedButUsed(*this); } + // A global-module-fragment is only permitted within a module unit. + bool DiagnosedMissingModuleDeclaration = false; + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment && + !ModuleScopes.back().ImplicitGlobalModuleFragment) { + Diag(ModuleScopes.back().BeginLoc, + diag::err_module_declaration_missing_after_global_module_introducer); + DiagnosedMissingModuleDeclaration = true; + } + if (TUKind == TU_Module) { // If we are building a module interface unit, we need to have seen the // module declaration by now. if (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface && (ModuleScopes.empty() || - ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)) { + !ModuleScopes.back().Module->isModulePurview()) && + !DiagnosedMissingModuleDeclaration) { // FIXME: Make a better guess as to where to put the module declaration. Diag(getSourceManager().getLocForStartOfFile( getSourceManager().getMainFileID()), @@ -1325,6 +1360,190 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { return Builder; } +// Print notes showing how we can reach FD starting from an a priori +// known-callable function. +static void emitCallStackNotes(Sema &S, FunctionDecl *FD) { + auto FnIt = S.DeviceKnownEmittedFns.find(FD); + while (FnIt != S.DeviceKnownEmittedFns.end()) { + DiagnosticBuilder Builder( + S.Diags.Report(FnIt->second.Loc, diag::note_called_by)); + Builder << FnIt->second.FD; + Builder.setForceEmit(); + + FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD); + } +} + +// Emit any deferred diagnostics for FD and erase them from the map in which +// they're stored. +static void emitDeferredDiags(Sema &S, FunctionDecl *FD) { + auto It = S.DeviceDeferredDiags.find(FD); + if (It == S.DeviceDeferredDiags.end()) + return; + bool HasWarningOrError = false; + for (PartialDiagnosticAt &PDAt : It->second) { + const SourceLocation &Loc = PDAt.first; + const PartialDiagnostic &PD = PDAt.second; + HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel( + PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning; + DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID())); + Builder.setForceEmit(); + PD.Emit(Builder); + } + S.DeviceDeferredDiags.erase(It); + + // FIXME: Should this be called after every warning/error emitted in the loop + // above, instead of just once per function? That would be consistent with + // how we handle immediate errors, but it also seems like a bit much. + if (HasWarningOrError) + emitCallStackNotes(S, FD); +} + +// In CUDA, there are some constructs which may appear in semantically-valid +// code, but trigger errors if we ever generate code for the function in which +// they appear. Essentially every construct you're not allowed to use on the +// device falls into this category, because you are allowed to use these +// constructs in a __host__ __device__ function, but only if that function is +// never codegen'ed on the device. +// +// To handle semantic checking for these constructs, we keep track of the set of +// functions we know will be emitted, either because we could tell a priori that +// they would be emitted, or because they were transitively called by a +// known-emitted function. +// +// We also keep a partial call graph of which not-known-emitted functions call +// which other not-known-emitted functions. +// +// When we see something which is illegal if the current function is emitted +// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or +// CheckCUDACall), we first check if the current function is known-emitted. If +// so, we immediately output the diagnostic. +// +// Otherwise, we "defer" the diagnostic. It sits in Sema::DeviceDeferredDiags +// until we discover that the function is known-emitted, at which point we take +// it out of this map and emit the diagnostic. + +Sema::DeviceDiagBuilder::DeviceDiagBuilder(Kind K, SourceLocation Loc, + unsigned DiagID, FunctionDecl *Fn, + Sema &S) + : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn), + ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) { + switch (K) { + case K_Nop: + break; + case K_Immediate: + case K_ImmediateWithCallStack: + ImmediateDiag.emplace(S.Diag(Loc, DiagID)); + break; + case K_Deferred: + assert(Fn && "Must have a function to attach the deferred diag to."); + auto &Diags = S.DeviceDeferredDiags[Fn]; + PartialDiagId.emplace(Diags.size()); + Diags.emplace_back(Loc, S.PDiag(DiagID)); + break; + } +} + +Sema::DeviceDiagBuilder::DeviceDiagBuilder(DeviceDiagBuilder &&D) + : S(D.S), Loc(D.Loc), DiagID(D.DiagID), Fn(D.Fn), + ShowCallStack(D.ShowCallStack), ImmediateDiag(D.ImmediateDiag), + PartialDiagId(D.PartialDiagId) { + // Clean the previous diagnostics. + D.ShowCallStack = false; + D.ImmediateDiag.reset(); + D.PartialDiagId.reset(); +} + +Sema::DeviceDiagBuilder::~DeviceDiagBuilder() { + if (ImmediateDiag) { + // Emit our diagnostic and, if it was a warning or error, output a callstack + // if Fn isn't a priori known-emitted. + bool IsWarningOrError = S.getDiagnostics().getDiagnosticLevel( + DiagID, Loc) >= DiagnosticsEngine::Warning; + ImmediateDiag.reset(); // Emit the immediate diag. + if (IsWarningOrError && ShowCallStack) + emitCallStackNotes(S, Fn); + } else { + assert((!PartialDiagId || ShowCallStack) && + "Must always show call stack for deferred diags."); + } +} + +// Indicate that this function (and thus everything it transtively calls) will +// be codegen'ed, and emit any deferred diagnostics on this function and its +// (transitive) callees. +void Sema::markKnownEmitted( + Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee, + SourceLocation OrigLoc, + const llvm::function_ref<bool(Sema &, FunctionDecl *)> IsKnownEmitted) { + // Nothing to do if we already know that FD is emitted. + if (IsKnownEmitted(S, OrigCallee)) { + assert(!S.DeviceCallGraph.count(OrigCallee)); + return; + } + + // We've just discovered that OrigCallee is known-emitted. Walk our call + // graph to see what else we can now discover also must be emitted. + + struct CallInfo { + FunctionDecl *Caller; + FunctionDecl *Callee; + SourceLocation Loc; + }; + llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}}; + llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen; + Seen.insert(OrigCallee); + while (!Worklist.empty()) { + CallInfo C = Worklist.pop_back_val(); + assert(!IsKnownEmitted(S, C.Callee) && + "Worklist should not contain known-emitted functions."); + S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc}; + emitDeferredDiags(S, C.Callee); + + // If this is a template instantiation, explore its callgraph as well: + // Non-dependent calls are part of the template's callgraph, while dependent + // calls are part of to the instantiation's call graph. + if (auto *Templ = C.Callee->getPrimaryTemplate()) { + FunctionDecl *TemplFD = Templ->getAsFunction(); + if (!Seen.count(TemplFD) && !S.DeviceKnownEmittedFns.count(TemplFD)) { + Seen.insert(TemplFD); + Worklist.push_back( + {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc}); + } + } + + // Add all functions called by Callee to our worklist. + auto CGIt = S.DeviceCallGraph.find(C.Callee); + if (CGIt == S.DeviceCallGraph.end()) + continue; + + for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc : + CGIt->second) { + FunctionDecl *NewCallee = FDLoc.first; + SourceLocation CallLoc = FDLoc.second; + if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee)) + continue; + Seen.insert(NewCallee); + Worklist.push_back( + {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc}); + } + + // C.Callee is now known-emitted, so we no longer need to maintain its list + // of callees in DeviceCallGraph. + S.DeviceCallGraph.erase(CGIt); + } +} + +Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) { + if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + return diagIfOpenMPDeviceCode(Loc, DiagID); + if (getLangOpts().CUDA) + return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) + : CUDADiagIfHostCode(Loc, DiagID); + return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID, + getCurFunctionDecl(), *this); +} + /// Looks through the macro-expansion chain for the given /// location, looking for a macro expansion with the given name. /// If one is found, returns true and sets the location to that @@ -1409,7 +1628,7 @@ void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) { } // Check that the type of the VarDecl has an accessible copy constructor and -// resolve its destructor's exception spefication. +// resolve its destructor's exception specification. static void checkEscapingByref(VarDecl *VD, Sema &S) { QualType T = VD->getType(); EnterExpressionEvaluationContext scope( @@ -1426,7 +1645,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) { S.Context.setBlockVarCopyInit(VD, Init, S.canThrow(Init)); } - // The destructor's exception spefication is needed when IRGen generates + // The destructor's exception specification is needed when IRGen generates // block copy/destroy functions. Resolve it here. if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) if (CXXDestructorDecl *DD = RD->getDestructor()) { @@ -1573,7 +1792,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { // an associated template parameter list. LambdaScopeInfo *Sema::getCurGenericLambda() { if (LambdaScopeInfo *LSI = getCurLambda()) { - return (LSI->AutoTemplateParams.size() || + return (LSI->TemplateParams.size() || LSI->GLTemplateParameterList) ? LSI : nullptr; } return nullptr; diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 69084589ef..b6fbbbff91 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1,9 +1,8 @@ //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -127,8 +126,7 @@ struct EffectiveContext { bool includesClass(const CXXRecordDecl *R) const { R = R->getCanonicalDecl(); - return std::find(Records.begin(), Records.end(), R) - != Records.end(); + return llvm::find(Records, R) != Records.end(); } /// Retrieves the innermost "useful" context. Can be null if we're diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 2bc1b769f7..e1929e3ec2 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -1,9 +1,8 @@ //===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -523,6 +522,7 @@ attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) { void Sema::ActOnPragmaAttributeAttribute( ParsedAttr &Attribute, SourceLocation PragmaLoc, attr::ParsedSubjectMatchRuleSet Rules) { + Attribute.setIsPragmaClangAttribute(); SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules; // Gather the subject match rules that are supported by the attribute. SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> @@ -680,6 +680,8 @@ void Sema::AddPragmaAttributes(Scope *S, Decl *D) { for (auto &Entry : Group.Entries) { ParsedAttr *Attribute = Entry.Attribute; assert(Attribute && "Expected an attribute"); + assert(Attribute->isPragmaClangAttribute() && + "expected #pragma clang attribute"); // Ensure that the attribute can be applied to the given declaration. bool Applies = false; diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp index ffc7288985..d062e8b201 100644 --- a/lib/Sema/SemaCUDA.cpp +++ b/lib/Sema/SemaCUDA.cpp @@ -1,9 +1,8 @@ //===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file @@ -14,6 +13,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/Cuda.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" @@ -42,9 +42,8 @@ ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, SourceLocation GGGLoc) { FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); if (!ConfigDecl) - return ExprError( - Diag(LLLLoc, diag::err_undeclared_var_use) - << (getLangOpts().HIP ? "hipConfigureCall" : "cudaConfigureCall")); + return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) + << getCudaConfigureFuncName()); QualType ConfigQTy = ConfigDecl->getType(); DeclRefExpr *ConfigDR = new (Context) @@ -587,78 +586,6 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); } -// In CUDA, there are some constructs which may appear in semantically-valid -// code, but trigger errors if we ever generate code for the function in which -// they appear. Essentially every construct you're not allowed to use on the -// device falls into this category, because you are allowed to use these -// constructs in a __host__ __device__ function, but only if that function is -// never codegen'ed on the device. -// -// To handle semantic checking for these constructs, we keep track of the set of -// functions we know will be emitted, either because we could tell a priori that -// they would be emitted, or because they were transitively called by a -// known-emitted function. -// -// We also keep a partial call graph of which not-known-emitted functions call -// which other not-known-emitted functions. -// -// When we see something which is illegal if the current function is emitted -// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or -// CheckCUDACall), we first check if the current function is known-emitted. If -// so, we immediately output the diagnostic. -// -// Otherwise, we "defer" the diagnostic. It sits in Sema::CUDADeferredDiags -// until we discover that the function is known-emitted, at which point we take -// it out of this map and emit the diagnostic. - -Sema::CUDADiagBuilder::CUDADiagBuilder(Kind K, SourceLocation Loc, - unsigned DiagID, FunctionDecl *Fn, - Sema &S) - : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn), - ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) { - switch (K) { - case K_Nop: - break; - case K_Immediate: - case K_ImmediateWithCallStack: - ImmediateDiag.emplace(S.Diag(Loc, DiagID)); - break; - case K_Deferred: - assert(Fn && "Must have a function to attach the deferred diag to."); - PartialDiag.emplace(S.PDiag(DiagID)); - break; - } -} - -// Print notes showing how we can reach FD starting from an a priori -// known-callable function. -static void EmitCallStackNotes(Sema &S, FunctionDecl *FD) { - auto FnIt = S.CUDAKnownEmittedFns.find(FD); - while (FnIt != S.CUDAKnownEmittedFns.end()) { - DiagnosticBuilder Builder( - S.Diags.Report(FnIt->second.Loc, diag::note_called_by)); - Builder << FnIt->second.FD; - Builder.setForceEmit(); - - FnIt = S.CUDAKnownEmittedFns.find(FnIt->second.FD); - } -} - -Sema::CUDADiagBuilder::~CUDADiagBuilder() { - if (ImmediateDiag) { - // Emit our diagnostic and, if it was a warning or error, output a callstack - // if Fn isn't a priori known-emitted. - bool IsWarningOrError = S.getDiagnostics().getDiagnosticLevel( - DiagID, Loc) >= DiagnosticsEngine::Warning; - ImmediateDiag.reset(); // Emit the immediate diag. - if (IsWarningOrError && ShowCallStack) - EmitCallStackNotes(S, Fn); - } else if (PartialDiag) { - assert(ShowCallStack && "Must always show call stack for deferred diags."); - S.CUDADeferredDiags[Fn].push_back({Loc, std::move(*PartialDiag)}); - } -} - // Do we know that we will eventually codegen the given function? static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { // Templates are emitted when they're instantiated. @@ -690,152 +617,69 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { // Otherwise, the function is known-emitted if it's in our set of // known-emitted functions. - return S.CUDAKnownEmittedFns.count(FD) > 0; + return S.DeviceKnownEmittedFns.count(FD) > 0; } -Sema::CUDADiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, - unsigned DiagID) { +Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - CUDADiagBuilder::Kind DiagKind = [&] { + DeviceDiagBuilder::Kind DiagKind = [this] { switch (CurrentCUDATarget()) { case CFT_Global: case CFT_Device: - return CUDADiagBuilder::K_Immediate; + return DeviceDiagBuilder::K_Immediate; case CFT_HostDevice: // An HD function counts as host code if we're compiling for host, and // device code if we're compiling for device. Defer any errors in device // mode until the function is known-emitted. if (getLangOpts().CUDAIsDevice) { return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)) - ? CUDADiagBuilder::K_ImmediateWithCallStack - : CUDADiagBuilder::K_Deferred; + ? DeviceDiagBuilder::K_ImmediateWithCallStack + : DeviceDiagBuilder::K_Deferred; } - return CUDADiagBuilder::K_Nop; + return DeviceDiagBuilder::K_Nop; default: - return CUDADiagBuilder::K_Nop; + return DeviceDiagBuilder::K_Nop; } }(); - return CUDADiagBuilder(DiagKind, Loc, DiagID, - dyn_cast<FunctionDecl>(CurContext), *this); + return DeviceDiagBuilder(DiagKind, Loc, DiagID, + dyn_cast<FunctionDecl>(CurContext), *this); } -Sema::CUDADiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc, - unsigned DiagID) { +Sema::DeviceDiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc, + unsigned DiagID) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - CUDADiagBuilder::Kind DiagKind = [&] { + DeviceDiagBuilder::Kind DiagKind = [this] { switch (CurrentCUDATarget()) { case CFT_Host: - return CUDADiagBuilder::K_Immediate; + return DeviceDiagBuilder::K_Immediate; case CFT_HostDevice: // An HD function counts as host code if we're compiling for host, and // device code if we're compiling for device. Defer any errors in device // mode until the function is known-emitted. if (getLangOpts().CUDAIsDevice) - return CUDADiagBuilder::K_Nop; + return DeviceDiagBuilder::K_Nop; return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)) - ? CUDADiagBuilder::K_ImmediateWithCallStack - : CUDADiagBuilder::K_Deferred; + ? DeviceDiagBuilder::K_ImmediateWithCallStack + : DeviceDiagBuilder::K_Deferred; default: - return CUDADiagBuilder::K_Nop; + return DeviceDiagBuilder::K_Nop; } }(); - return CUDADiagBuilder(DiagKind, Loc, DiagID, - dyn_cast<FunctionDecl>(CurContext), *this); -} - -// Emit any deferred diagnostics for FD and erase them from the map in which -// they're stored. -static void EmitDeferredDiags(Sema &S, FunctionDecl *FD) { - auto It = S.CUDADeferredDiags.find(FD); - if (It == S.CUDADeferredDiags.end()) - return; - bool HasWarningOrError = false; - for (PartialDiagnosticAt &PDAt : It->second) { - const SourceLocation &Loc = PDAt.first; - const PartialDiagnostic &PD = PDAt.second; - HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel( - PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning; - DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID())); - Builder.setForceEmit(); - PD.Emit(Builder); - } - S.CUDADeferredDiags.erase(It); - - // FIXME: Should this be called after every warning/error emitted in the loop - // above, instead of just once per function? That would be consistent with - // how we handle immediate errors, but it also seems like a bit much. - if (HasWarningOrError) - EmitCallStackNotes(S, FD); -} - -// Indicate that this function (and thus everything it transtively calls) will -// be codegen'ed, and emit any deferred diagnostics on this function and its -// (transitive) callees. -static void MarkKnownEmitted(Sema &S, FunctionDecl *OrigCaller, - FunctionDecl *OrigCallee, SourceLocation OrigLoc) { - // Nothing to do if we already know that FD is emitted. - if (IsKnownEmitted(S, OrigCallee)) { - assert(!S.CUDACallGraph.count(OrigCallee)); - return; - } - - // We've just discovered that OrigCallee is known-emitted. Walk our call - // graph to see what else we can now discover also must be emitted. - - struct CallInfo { - FunctionDecl *Caller; - FunctionDecl *Callee; - SourceLocation Loc; - }; - llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}}; - llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen; - Seen.insert(OrigCallee); - while (!Worklist.empty()) { - CallInfo C = Worklist.pop_back_val(); - assert(!IsKnownEmitted(S, C.Callee) && - "Worklist should not contain known-emitted functions."); - S.CUDAKnownEmittedFns[C.Callee] = {C.Caller, C.Loc}; - EmitDeferredDiags(S, C.Callee); - - // If this is a template instantiation, explore its callgraph as well: - // Non-dependent calls are part of the template's callgraph, while dependent - // calls are part of to the instantiation's call graph. - if (auto *Templ = C.Callee->getPrimaryTemplate()) { - FunctionDecl *TemplFD = Templ->getAsFunction(); - if (!Seen.count(TemplFD) && !S.CUDAKnownEmittedFns.count(TemplFD)) { - Seen.insert(TemplFD); - Worklist.push_back( - {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc}); - } - } - - // Add all functions called by Callee to our worklist. - auto CGIt = S.CUDACallGraph.find(C.Callee); - if (CGIt == S.CUDACallGraph.end()) - continue; - - for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc : - CGIt->second) { - FunctionDecl *NewCallee = FDLoc.first; - SourceLocation CallLoc = FDLoc.second; - if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee)) - continue; - Seen.insert(NewCallee); - Worklist.push_back( - {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc}); - } - - // C.Callee is now known-emitted, so we no longer need to maintain its list - // of callees in CUDACallGraph. - S.CUDACallGraph.erase(CGIt); - } + return DeviceDiagBuilder(DiagKind, Loc, DiagID, + dyn_cast<FunctionDecl>(CurContext), *this); } bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); assert(Callee && "Callee may not be null."); + + auto &ExprEvalCtx = ExprEvalContexts.back(); + if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated()) + return true; + // FIXME: Is bailing out early correct here? Should we instead assume that // the caller is a global initializer? FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext); @@ -849,7 +693,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // Host-side references to a __global__ function refer to the stub, so the // function itself is never emitted and therefore should not be marked. if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global) - MarkKnownEmitted(*this, Caller, Callee, Loc); + markKnownEmitted(*this, Caller, Callee, Loc, IsKnownEmitted); } else { // If we have // host fn calls kernel fn calls host+device, @@ -858,26 +702,27 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // that, when compiling for host, only HD functions actually called from the // host get marked as known-emitted. if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global) - CUDACallGraph[Caller].insert({Callee, Loc}); + DeviceCallGraph[Caller].insert({Callee, Loc}); } - CUDADiagBuilder::Kind DiagKind = [&] { + DeviceDiagBuilder::Kind DiagKind = [this, Caller, Callee, + CallerKnownEmitted] { switch (IdentifyCUDAPreference(Caller, Callee)) { case CFP_Never: - return CUDADiagBuilder::K_Immediate; + return DeviceDiagBuilder::K_Immediate; case CFP_WrongSide: assert(Caller && "WrongSide calls require a non-null caller"); // If we know the caller will be emitted, we know this wrong-side call // will be emitted, so it's an immediate error. Otherwise, defer the // error until we know the caller is emitted. - return CallerKnownEmitted ? CUDADiagBuilder::K_ImmediateWithCallStack - : CUDADiagBuilder::K_Deferred; + return CallerKnownEmitted ? DeviceDiagBuilder::K_ImmediateWithCallStack + : DeviceDiagBuilder::K_Deferred; default: - return CUDADiagBuilder::K_Nop; + return DeviceDiagBuilder::K_Nop; } }(); - if (DiagKind == CUDADiagBuilder::K_Nop) + if (DiagKind == DeviceDiagBuilder::K_Nop) return true; // Avoid emitting this error twice for the same location. Using a hashtable @@ -887,13 +732,13 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { if (!LocsWithCUDACallDiags.insert({Caller, Loc}).second) return true; - CUDADiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this) + DeviceDiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this) << IdentifyCUDATarget(Callee) << Callee << IdentifyCUDATarget(Caller); - CUDADiagBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl, - Caller, *this) + DeviceDiagBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl, + Caller, *this) << Callee; - return DiagKind != CUDADiagBuilder::K_Immediate && - DiagKind != CUDADiagBuilder::K_ImmediateWithCallStack; + return DiagKind != DeviceDiagBuilder::K_Immediate && + DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack; } void Sema::CUDASetLambdaAttrs(CXXMethodDecl *Method) { @@ -958,3 +803,16 @@ void Sema::inheritCUDATargetAttrs(FunctionDecl *FD, copyAttrIfPresent<CUDAHostAttr>(*this, FD, TemplateFD); copyAttrIfPresent<CUDADeviceAttr>(*this, FD, TemplateFD); } + +std::string Sema::getCudaConfigureFuncName() const { + if (getLangOpts().HIP) + return "hipConfigureCall"; + + // New CUDA kernel launch sequence. + if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(), + CudaFeature::CUDA_USES_NEW_LAUNCH)) + return "__cudaPushCallConfiguration"; + + // Legacy CUDA kernel configuration call + return "cudaConfigureCall"; +} diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 2354ffe7fb..93912dae03 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -1,9 +1,8 @@ //===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -430,8 +429,9 @@ namespace { // Callback to only accept typo corrections that can be a valid C++ member // intializer: either a non-static field member or a base class. -class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { - public: +class NestedNameSpecifierValidatorCCC final + : public CorrectionCandidateCallback { +public: explicit NestedNameSpecifierValidatorCCC(Sema &SRef) : SRef(SRef) {} @@ -439,6 +439,10 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl()); } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this); + } + private: Sema &SRef; }; @@ -615,9 +619,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); Found.clear(); + NestedNameSpecifierValidatorCCC CCC(*this); if (TypoCorrection Corrected = CorrectTypo( - Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, - llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this), + Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, CCC, CTK_ErrorRecovery, LookupCtx, EnteringContext)) { if (LookupCtx) { bool DroppedSpecifier = diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 0b4645e11c..21a4d107ba 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1,9 +1,8 @@ //===--- SemaCast.cpp - Semantic Analysis for Casts -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -400,11 +399,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, break; } - S.Diag(range.getBegin(), msg) - << CT << srcType << destType - << range << src->getSourceRange(); - - candidates.NoteCandidates(S, howManyCandidates, src); + candidates.NoteCandidates( + PartialDiagnosticAt(range.getBegin(), + S.PDiag(msg) << CT << srcType << destType << range + << src->getSourceRange()), + S, howManyCandidates, src); return true; } @@ -2213,7 +2212,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, /*CheckObjCLifetime=*/CStyle)) SuccessResult = getCastAwayConstnessCastKind(CACK, msg); - if (IsLValueCast) { + if (IsAddressSpaceConversion(SrcType, DestType)) { + Kind = CK_AddressSpaceConversion; + assert(SrcType->isPointerType() && DestType->isPointerType()); + if (!CStyle && + !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( + SrcType->getPointeeType().getQualifiers())) { + SuccessResult = TC_Failed; + } + } else if (IsLValueCast) { Kind = CK_LValueBitCast; } else if (DestType->isObjCObjectPointerType()) { Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr); @@ -2223,8 +2230,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } else { Kind = CK_BitCast; } - } else if (IsAddressSpaceConversion(SrcType, DestType)) { - Kind = CK_AddressSpaceConversion; } else { Kind = CK_BitCast; } @@ -2279,6 +2284,41 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return SuccessResult; } +static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, + QualType DestType, bool CStyle, + unsigned &msg) { + if (!Self.getLangOpts().OpenCL) + // FIXME: As compiler doesn't have any information about overlapping addr + // spaces at the moment we have to be permissive here. + return TC_NotApplicable; + // Even though the logic below is general enough and can be applied to + // non-OpenCL mode too, we fast-path above because no other languages + // define overlapping address spaces currently. + auto SrcType = SrcExpr.get()->getType(); + auto SrcPtrType = SrcType->getAs<PointerType>(); + if (!SrcPtrType) + return TC_NotApplicable; + auto DestPtrType = DestType->getAs<PointerType>(); + if (!DestPtrType) + return TC_NotApplicable; + auto SrcPointeeType = SrcPtrType->getPointeeType(); + auto DestPointeeType = DestPtrType->getPointeeType(); + if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()) + return TC_NotApplicable; + if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { + msg = diag::err_bad_cxx_cast_addr_space_mismatch; + return TC_Failed; + } + auto SrcPointeeTypeWithoutAS = + Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType()); + auto DestPointeeTypeWithoutAS = + Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType()); + return Self.Context.hasSameType(SrcPointeeTypeWithoutAS, + DestPointeeTypeWithoutAS) + ? TC_Success + : TC_NotApplicable; +} + void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { // In OpenCL only conversions between pointers to objects in overlapping // addr spaces are allowed. v2.0 s6.5.5 - Generic addr space overlaps @@ -2373,30 +2413,35 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, // listed above, the interpretation that appears first in the list is used, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... + // Note that for address space we check compatibility after const_cast. unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType, - /*CStyle*/true, msg); + /*CStyle*/ true, msg); if (SrcExpr.isInvalid()) return; if (isValidCast(tcr)) Kind = CK_NoOp; - Sema::CheckedConversionKind CCK - = FunctionalStyle? Sema::CCK_FunctionalCast - : Sema::CCK_CStyleCast; + Sema::CheckedConversionKind CCK = + FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { - // ... or if that is not possible, a static_cast, ignoring const, ... - tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, - msg, Kind, BasePath, ListInitialization); + tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg); if (SrcExpr.isInvalid()) return; - if (tcr == TC_NotApplicable) { - // ... and finally a reinterpret_cast, ignoring const. - tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true, - OpRange, msg, Kind); + // ... or if that is not possible, a static_cast, ignoring const, ... + tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind, + BasePath, ListInitialization); if (SrcExpr.isInvalid()) return; + + if (tcr == TC_NotApplicable) { + // ... and finally a reinterpret_cast, ignoring const. + tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true, + OpRange, msg, Kind); + if (SrcExpr.isInvalid()) + return; + } } } @@ -2427,8 +2472,6 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } } - checkAddressSpaceCast(SrcExpr.get()->getType(), DestType); - if (isValidCast(tcr)) { if (Kind == CK_BitCast) checkCastAlign(); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 8dc1fdb769..d0479b832f 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1,9 +1,8 @@ //===- SemaChecking.cpp - Extra Semantic Checking -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -236,47 +235,6 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { return false; } -static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, - CallExpr *TheCall, unsigned SizeIdx, - unsigned DstSizeIdx, - StringRef LikelyMacroName) { - if (TheCall->getNumArgs() <= SizeIdx || - TheCall->getNumArgs() <= DstSizeIdx) - return; - - const Expr *SizeArg = TheCall->getArg(SizeIdx); - const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx); - - Expr::EvalResult SizeResult, DstSizeResult; - - // find out if both sizes are known at compile time - if (!SizeArg->EvaluateAsInt(SizeResult, S.Context) || - !DstSizeArg->EvaluateAsInt(DstSizeResult, S.Context)) - return; - - llvm::APSInt Size = SizeResult.Val.getInt(); - llvm::APSInt DstSize = DstSizeResult.Val.getInt(); - - if (Size.ule(DstSize)) - return; - - // Confirmed overflow, so generate the diagnostic. - StringRef FunctionName = FDecl->getName(); - SourceLocation SL = TheCall->getBeginLoc(); - SourceManager &SM = S.getSourceManager(); - // If we're in an expansion of a macro whose name corresponds to this builtin, - // use the simple macro name and location. - if (SL.isMacroID() && Lexer::getImmediateMacroName(SL, SM, S.getLangOpts()) == - LikelyMacroName) { - FunctionName = LikelyMacroName; - SL = SM.getImmediateMacroCallerLoc(SL); - } - - S.Diag(SL, diag::warn_memcpy_chk_overflow) - << FunctionName << DstSize.toString(/*Radix=*/10) - << Size.toString(/*Radix=*/10); -} - static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { if (checkArgCount(S, BuiltinCall, 2)) return true; @@ -340,6 +298,148 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { return false; } +/// Check a call to BuiltinID for buffer overflows. If BuiltinID is a +/// __builtin_*_chk function, then use the object size argument specified in the +/// source. Otherwise, infer the object size using __builtin_object_size. +void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, + CallExpr *TheCall) { + // FIXME: There are some more useful checks we could be doing here: + // - Analyze the format string of sprintf to see how much of buffer is used. + // - Evaluate strlen of strcpy arguments, use as object size. + + if (TheCall->isValueDependent() || TheCall->isTypeDependent()) + return; + + unsigned BuiltinID = FD->getBuiltinID(/*ConsiderWrappers=*/true); + if (!BuiltinID) + return; + + unsigned DiagID = 0; + bool IsChkVariant = false; + unsigned SizeIndex, ObjectIndex; + switch (BuiltinID) { + default: + return; + case Builtin::BI__builtin___memcpy_chk: + case Builtin::BI__builtin___memmove_chk: + case Builtin::BI__builtin___memset_chk: + case Builtin::BI__builtin___strlcat_chk: + case Builtin::BI__builtin___strlcpy_chk: + case Builtin::BI__builtin___strncat_chk: + case Builtin::BI__builtin___strncpy_chk: + case Builtin::BI__builtin___stpncpy_chk: + case Builtin::BI__builtin___memccpy_chk: { + DiagID = diag::warn_builtin_chk_overflow; + IsChkVariant = true; + SizeIndex = TheCall->getNumArgs() - 2; + ObjectIndex = TheCall->getNumArgs() - 1; + break; + } + + case Builtin::BI__builtin___snprintf_chk: + case Builtin::BI__builtin___vsnprintf_chk: { + DiagID = diag::warn_builtin_chk_overflow; + IsChkVariant = true; + SizeIndex = 1; + ObjectIndex = 3; + break; + } + + case Builtin::BIstrncat: + case Builtin::BI__builtin_strncat: + case Builtin::BIstrncpy: + case Builtin::BI__builtin_strncpy: + case Builtin::BIstpncpy: + case Builtin::BI__builtin_stpncpy: { + // Whether these functions overflow depends on the runtime strlen of the + // string, not just the buffer size, so emitting the "always overflow" + // diagnostic isn't quite right. We should still diagnose passing a buffer + // size larger than the destination buffer though; this is a runtime abort + // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise. + DiagID = diag::warn_fortify_source_size_mismatch; + SizeIndex = TheCall->getNumArgs() - 1; + ObjectIndex = 0; + break; + } + + case Builtin::BImemcpy: + case Builtin::BI__builtin_memcpy: + case Builtin::BImemmove: + case Builtin::BI__builtin_memmove: + case Builtin::BImemset: + case Builtin::BI__builtin_memset: { + DiagID = diag::warn_fortify_source_overflow; + SizeIndex = TheCall->getNumArgs() - 1; + ObjectIndex = 0; + break; + } + case Builtin::BIsnprintf: + case Builtin::BI__builtin_snprintf: + case Builtin::BIvsnprintf: + case Builtin::BI__builtin_vsnprintf: { + DiagID = diag::warn_fortify_source_size_mismatch; + SizeIndex = 1; + ObjectIndex = 0; + break; + } + } + + llvm::APSInt ObjectSize; + // For __builtin___*_chk, the object size is explicitly provided by the caller + // (usually using __builtin_object_size). Use that value to check this call. + if (IsChkVariant) { + Expr::EvalResult Result; + Expr *SizeArg = TheCall->getArg(ObjectIndex); + if (!SizeArg->EvaluateAsInt(Result, getASTContext())) + return; + ObjectSize = Result.Val.getInt(); + + // Otherwise, try to evaluate an imaginary call to __builtin_object_size. + } else { + // If the parameter has a pass_object_size attribute, then we should use its + // (potentially) more strict checking mode. Otherwise, conservatively assume + // type 0. + int BOSType = 0; + if (const auto *POS = + FD->getParamDecl(ObjectIndex)->getAttr<PassObjectSizeAttr>()) + BOSType = POS->getType(); + + Expr *ObjArg = TheCall->getArg(ObjectIndex); + uint64_t Result; + if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) + return; + // Get the object size in the target's size_t width. + const TargetInfo &TI = getASTContext().getTargetInfo(); + unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); + ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); + } + + // Evaluate the number of bytes of the object that this call will use. + Expr::EvalResult Result; + Expr *UsedSizeArg = TheCall->getArg(SizeIndex); + if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext())) + return; + llvm::APSInt UsedSize = Result.Val.getInt(); + + if (UsedSize.ule(ObjectSize)) + return; + + StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID); + // Skim off the details of whichever builtin was called to produce a better + // diagnostic, as it's unlikley that the user wrote the __builtin explicitly. + if (IsChkVariant) { + FunctionName = FunctionName.drop_front(std::strlen("__builtin___")); + FunctionName = FunctionName.drop_back(std::strlen("_chk")); + } else if (FunctionName.startswith("__builtin_")) { + FunctionName = FunctionName.drop_front(std::strlen("__builtin_")); + } + + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(DiagID) + << FunctionName << ObjectSize.toString(/*Radix=*/10) + << UsedSize.toString(/*Radix=*/10)); +} + static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, Scope::ScopeFlags NeededScopeFlags, unsigned DiagID) { @@ -1077,6 +1177,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinAssumeAligned(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); @@ -1098,10 +1199,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (checkArgCount(*this, TheCall, 1)) return true; TheCall->setType(Context.IntTy); break; - case Builtin::BI__builtin_constant_p: + case Builtin::BI__builtin_constant_p: { if (checkArgCount(*this, TheCall, 1)) return true; + ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); + if (Arg.isInvalid()) return true; + TheCall->setArg(0, Arg.get()); TheCall->setType(Context.IntTy); break; + } case Builtin::BI__builtin_launder: return SemaBuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: @@ -1302,42 +1407,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } - - // check secure string manipulation functions where overflows - // are detectable at compile time - case Builtin::BI__builtin___memcpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memcpy"); - break; - case Builtin::BI__builtin___memmove_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memmove"); - break; - case Builtin::BI__builtin___memset_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memset"); - break; - case Builtin::BI__builtin___strlcat_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strlcat"); - break; - case Builtin::BI__builtin___strlcpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strlcpy"); - break; - case Builtin::BI__builtin___strncat_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strncat"); - break; - case Builtin::BI__builtin___strncpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strncpy"); - break; - case Builtin::BI__builtin___stpncpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "stpncpy"); - break; - case Builtin::BI__builtin___memccpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 3, 4, "memccpy"); - break; - case Builtin::BI__builtin___snprintf_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3, "snprintf"); - break; - case Builtin::BI__builtin___vsnprintf_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3, "vsnprintf"); - break; case Builtin::BI__builtin_call_with_static_chain: if (SemaBuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); @@ -1806,6 +1875,16 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, BuiltinID == AArch64::BI__builtin_arm_wsr64) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + // Memory Tagging Extensions (MTE) Intrinsics + if (BuiltinID == AArch64::BI__builtin_arm_irg || + BuiltinID == AArch64::BI__builtin_arm_addg || + BuiltinID == AArch64::BI__builtin_arm_gmi || + BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg || + BuiltinID == AArch64::BI__builtin_arm_subp) { + return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall); + } + if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || @@ -3364,9 +3443,13 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtdq2ps512_mask: case X86::BI__builtin_ia32_cvtudq2ps512_mask: case X86::BI__builtin_ia32_cvtpd2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2dq512_mask: case X86::BI__builtin_ia32_cvtpd2qq512_mask: + case X86::BI__builtin_ia32_cvtpd2udq512_mask: case X86::BI__builtin_ia32_cvtpd2uqq512_mask: + case X86::BI__builtin_ia32_cvtps2dq512_mask: case X86::BI__builtin_ia32_cvtps2qq512_mask: + case X86::BI__builtin_ia32_cvtps2udq512_mask: case X86::BI__builtin_ia32_cvtps2uqq512_mask: case X86::BI__builtin_ia32_cvtqq2pd512_mask: case X86::BI__builtin_ia32_cvtqq2ps512_mask: @@ -6029,6 +6112,160 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions +bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID == AArch64::BI__builtin_arm_irg) { + if (checkArgCount(*this, TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + ExprResult SecArg = DefaultLvalueConversion(Arg1); + if (SecArg.isInvalid()) + return true; + QualType SecArgType = SecArg.get()->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_addg) { + if (checkArgCount(*this, TheCall, 2)) + return true; + + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + + // Second arg must be an constant in range [0,15] + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + } + + if (BuiltinID == AArch64::BI__builtin_arm_gmi) { + if (checkArgCount(*this, TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + + QualType SecArgType = Arg1->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + TheCall->setType(Context.IntTy); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg) { + if (checkArgCount(*this, TheCall, 1)) + return true; + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + if (BuiltinID == AArch64::BI__builtin_arm_ldg) + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_subp) { + Expr *ArgA = TheCall->getArg(0); + Expr *ArgB = TheCall->getArg(1); + + ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA); + ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB); + + if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) + return true; + + QualType ArgTypeA = ArgExprA.get()->getType(); + QualType ArgTypeB = ArgExprB.get()->getType(); + + auto isNull = [&] (Expr *E) -> bool { + return E->isNullPointerConstant( + Context, Expr::NPC_ValueDependentIsNotNull); }; + + // argument should be either a pointer or null + if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "first" << ArgTypeA << ArgA->getSourceRange(); + + if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "second" << ArgTypeB << ArgB->getSourceRange(); + + // Ensure Pointee types are compatible + if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && + ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { + QualType pointeeA = ArgTypeA->getPointeeType(); + QualType pointeeB = ArgTypeB->getPointeeType(); + if (!Context.typesAreCompatible( + Context.getCanonicalType(pointeeA).getUnqualifiedType(), + Context.getCanonicalType(pointeeB).getUnqualifiedType())) { + return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange() + << ArgB->getSourceRange(); + } + } + + // at least one argument should be pointer type + if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); + + if (isNull(ArgA)) // adopt type of the other pointer + ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); + + if (isNull(ArgB)) + ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); + + TheCall->setArg(0, ArgExprA.get()); + TheCall->setArg(1, ArgExprB.get()); + TheCall->setType(Context.LongLongTy); + return false; + } + assert(false && "Unhandled ARM MTE intrinsic"); + return true; +} + /// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, @@ -7651,7 +7888,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier startSpecifier, specifierLen); // Check the length modifier is valid with the given conversion specifier. - if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), + S.getLangOpts())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_nonsensical_length); else if (!FS.hasStandardLengthModifier()) @@ -8155,7 +8393,8 @@ bool CheckScanfHandler::HandleScanfSpecifier( } // Check the length modifier is valid with the given conversion specifier. - if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), + S.getLangOpts())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_nonsensical_length); else if (!FS.hasStandardLengthModifier()) @@ -9172,23 +9411,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, getContainedDynamicClass(PointeeTy, IsContained)) { unsigned OperationType = 0; + const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp; // "overwritten" if we're warning about the destination for any call // but memcmp; otherwise a verb appropriate to the call. - if (ArgIdx != 0 || BId == Builtin::BImemcmp) { + if (ArgIdx != 0 || IsCmp) { if (BId == Builtin::BImemcpy) OperationType = 1; else if(BId == Builtin::BImemmove) OperationType = 2; - else if (BId == Builtin::BImemcmp) + else if (IsCmp) OperationType = 3; } - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_dyn_class_memaccess) - << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx) - << FnName << IsContained << ContainedRD << OperationType - << Call->getCallee()->getSourceRange()); + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_dyn_class_memaccess) + << (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName + << IsContained << ContainedRD << OperationType + << Call->getCallee()->getSourceRange()); } else if (PointeeTy.hasNonTrivialObjCLifetime() && BId != Builtin::BImemset) DiagRuntimeBehavior( @@ -10622,16 +10861,18 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { // The below checks assume source is floating point. if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return; - // If source is floating point but target is not. + // If source is floating point but target is an integer. + if (ResultBT->isInteger()) + return DiagnoseImpCast(S, E, E->getRHS()->getType(), E->getLHS()->getType(), + E->getExprLoc(), diag::warn_impcast_float_integer); + if (!ResultBT->isFloatingPoint()) - return DiagnoseFloatingImpCast(S, E, E->getRHS()->getType(), - E->getExprLoc()); - - // If both source and target are floating points. - // Builtin FP kinds are ordered by increasing FP rank. - if (ResultBT->getKind() < RBT->getKind() && - // We don't want to warn for system macro. - !S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) + return; + + // If both source and target are floating points, warn about losing precision. + int Order = S.getASTContext().getFloatingTypeSemanticOrder( + QualType(ResultBT, 0), QualType(RBT, 0)); + if (Order < 0 && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) // warn about dropping FP rank. DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), E->getOperatorLoc(), diag::warn_impcast_float_result_precision); @@ -10950,8 +11191,9 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (TargetBT && TargetBT->isFloatingPoint()) { // ...then warn if we're dropping FP rank. - // Builtin FP kinds are ordered by increasing FP rank. - if (SourceBT->getKind() > TargetBT->getKind()) { + int Order = S.getASTContext().getFloatingTypeSemanticOrder( + QualType(SourceBT, 0), QualType(TargetBT, 0)); + if (Order > 0) { // Don't warn about float constants that are precisely // representable in the target type. Expr::EvalResult result; @@ -10969,7 +11211,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); } // ... or possibly if we're increasing rank, too - else if (TargetBT->getKind() > SourceBT->getKind()) { + else if (Order < 0) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -11013,6 +11255,67 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, return; } + // Valid casts involving fixed point types should be accounted for here. + if (Source->isFixedPointType()) { + if (Target->isUnsaturatedFixedPointType()) { + Expr::EvalResult Result; + if (E->EvaluateAsFixedPoint(Result, S.Context, + Expr::SE_AllowSideEffects)) { + APFixedPoint Value = Result.Val.getFixedPoint(); + APFixedPoint MaxVal = S.Context.getFixedPointMax(T); + APFixedPoint MinVal = S.Context.getFixedPointMin(T); + if (Value > MaxVal || Value < MinVal) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_fixed_point_range) + << Value.toString() << T + << E->getSourceRange() + << clang::SourceRange(CC)); + return; + } + } + } else if (Target->isIntegerType()) { + Expr::EvalResult Result; + if (E->EvaluateAsFixedPoint(Result, S.Context, + Expr::SE_AllowSideEffects)) { + APFixedPoint FXResult = Result.Val.getFixedPoint(); + + bool Overflowed; + llvm::APSInt IntResult = FXResult.convertToInt( + S.Context.getIntWidth(T), + Target->isSignedIntegerOrEnumerationType(), &Overflowed); + + if (Overflowed) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_fixed_point_range) + << FXResult.toString() << T + << E->getSourceRange() + << clang::SourceRange(CC)); + return; + } + } + } + } else if (Target->isUnsaturatedFixedPointType()) { + if (Source->isIntegerType()) { + Expr::EvalResult Result; + if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { + llvm::APSInt Value = Result.Val.getInt(); + + bool Overflowed; + APFixedPoint IntResult = APFixedPoint::getFromIntValue( + Value, S.Context.getFixedPointSemantics(T), &Overflowed); + + if (Overflowed) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_fixed_point_range) + << Value.toString(/*radix=*/10) << T + << E->getSourceRange() + << clang::SourceRange(CC)); + return; + } + } + } + } + DiagnoseNullConversion(S, E, T, CC); S.DiscardMisalignedMemberAddress(Target, E); @@ -11464,6 +11767,9 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, } if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { + // Skip function template not specialized yet. + if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return; auto ParamIter = llvm::find(FD->parameters(), PV); assert(ParamIter != FD->param_end()); unsigned ParamNo = std::distance(FD->param_begin(), ParamIter); @@ -11641,12 +11947,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { class Seq { friend class SequenceTree; - unsigned Index = 0; + unsigned Index; explicit Seq(unsigned N) : Index(N) {} public: - Seq() = default; + Seq() : Index(0) {} }; SequenceTree() { Values.push_back(Value(0)); } @@ -11710,19 +12016,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; struct Usage { - Expr *Use = nullptr; + Expr *Use; SequenceTree::Seq Seq; - Usage() = default; + Usage() : Use(nullptr), Seq() {} }; struct UsageInfo { Usage Uses[UK_Count]; /// Have we issued a diagnostic for this variable already? - bool Diagnosed = false; + bool Diagnosed; - UsageInfo() = default; + UsageInfo() : Uses(), Diagnosed(false) {} }; using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>; @@ -11849,10 +12155,11 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { if (OtherKind == UK_Use) std::swap(Mod, ModOrUse); - SemaRef.Diag(Mod->getExprLoc(), - IsModMod ? diag::warn_unsequenced_mod_mod - : diag::warn_unsequenced_mod_use) - << O << SourceRange(ModOrUse->getExprLoc()); + SemaRef.DiagRuntimeBehavior( + Mod->getExprLoc(), {Mod, ModOrUse}, + SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod + : diag::warn_unsequenced_mod_use) + << O << SourceRange(ModOrUse->getExprLoc())); UI.Diagnosed = true; } @@ -12395,6 +12702,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, return; const Type *BaseType = ArrayTy->getElementType().getTypePtr(); + if (EffectiveType->isDependentType() || BaseType->isDependentType()) + return; Expr::EvalResult Result; if (!IndexExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) @@ -13787,8 +14096,7 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); if (isa<MemberExpr>(Op)) { - auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), - MisalignedMember(Op)); + auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op)); if (MA != MisalignedMembers.end() && (T->isIntegerType() || (T->isPointerType() && (T->getPointeeType()->isIncompleteType() || diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index d9f007a46d..4d23bf6b75 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1,9 +1,8 @@ //===---------------- SemaCodeComplete.cpp - Code Completion ----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -348,6 +347,202 @@ public: }; } // namespace +void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { + if (isa<BlockDecl>(S.CurContext)) { + if (sema::BlockScopeInfo *BSI = S.getCurBlock()) { + ComputeType = nullptr; + Type = BSI->ReturnType; + ExpectedLoc = Tok; + } + } else if (const auto *Function = dyn_cast<FunctionDecl>(S.CurContext)) { + ComputeType = nullptr; + Type = Function->getReturnType(); + ExpectedLoc = Tok; + } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(S.CurContext)) { + ComputeType = nullptr; + Type = Method->getReturnType(); + ExpectedLoc = Tok; + } +} + +void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) { + auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D); + ComputeType = nullptr; + Type = VD ? VD->getType() : QualType(); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterFunctionArgument( + SourceLocation Tok, llvm::function_ref<QualType()> ComputeType) { + this->ComputeType = ComputeType; + Type = QualType(); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok, + SourceLocation LParLoc) { + // expected type for parenthesized expression does not change. + if (ExpectedLoc == LParLoc) + ExpectedLoc = Tok; +} + +static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS, + tok::TokenKind Op) { + if (!LHS) + return QualType(); + + QualType LHSType = LHS->getType(); + if (LHSType->isPointerType()) { + if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal) + return S.getASTContext().getPointerDiffType(); + // Pointer difference is more common than subtracting an int from a pointer. + if (Op == tok::minus) + return LHSType; + } + + switch (Op) { + // No way to infer the type of RHS from LHS. + case tok::comma: + return QualType(); + // Prefer the type of the left operand for all of these. + // Arithmetic operations. + case tok::plus: + case tok::plusequal: + case tok::minus: + case tok::minusequal: + case tok::percent: + case tok::percentequal: + case tok::slash: + case tok::slashequal: + case tok::star: + case tok::starequal: + // Assignment. + case tok::equal: + // Comparison operators. + case tok::equalequal: + case tok::exclaimequal: + case tok::less: + case tok::lessequal: + case tok::greater: + case tok::greaterequal: + case tok::spaceship: + return LHS->getType(); + // Binary shifts are often overloaded, so don't try to guess those. + case tok::greatergreater: + case tok::greatergreaterequal: + case tok::lessless: + case tok::lesslessequal: + if (LHSType->isIntegralOrEnumerationType()) + return S.getASTContext().IntTy; + return QualType(); + // Logical operators, assume we want bool. + case tok::ampamp: + case tok::pipepipe: + case tok::caretcaret: + return S.getASTContext().BoolTy; + // Operators often used for bit manipulation are typically used with the type + // of the left argument. + case tok::pipe: + case tok::pipeequal: + case tok::caret: + case tok::caretequal: + case tok::amp: + case tok::ampequal: + if (LHSType->isIntegralOrEnumerationType()) + return LHSType; + return QualType(); + // RHS should be a pointer to a member of the 'LHS' type, but we can't give + // any particular type here. + case tok::periodstar: + case tok::arrowstar: + return QualType(); + default: + // FIXME(ibiryukov): handle the missing op, re-add the assertion. + // assert(false && "unhandled binary op"); + return QualType(); + } +} + +/// Get preferred type for an argument of an unary expression. \p ContextType is +/// preferred type of the whole unary expression. +static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType, + tok::TokenKind Op) { + switch (Op) { + case tok::exclaim: + return S.getASTContext().BoolTy; + case tok::amp: + if (!ContextType.isNull() && ContextType->isPointerType()) + return ContextType->getPointeeType(); + return QualType(); + case tok::star: + if (ContextType.isNull()) + return QualType(); + return S.getASTContext().getPointerType(ContextType.getNonReferenceType()); + case tok::plus: + case tok::minus: + case tok::tilde: + case tok::minusminus: + case tok::plusplus: + if (ContextType.isNull()) + return S.getASTContext().IntTy; + // leave as is, these operators typically return the same type. + return ContextType; + case tok::kw___real: + case tok::kw___imag: + return QualType(); + default: + assert(false && "unhandled unary op"); + return QualType(); + } +} + +void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, + tok::TokenKind Op) { + ComputeType = nullptr; + Type = getPreferredTypeOfBinaryRHS(S, LHS, Op); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok, + Expr *Base) { + if (!Base) + return; + // Do we have expected type for Base? + if (ExpectedLoc != Base->getBeginLoc()) + return; + // Keep the expected type, only update the location. + ExpectedLoc = Tok; + return; +} + +void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok, + tok::TokenKind OpKind, + SourceLocation OpLoc) { + ComputeType = nullptr; + Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok, + Expr *LHS) { + ComputeType = nullptr; + Type = S.getASTContext().IntTy; + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok, + QualType CastType) { + ComputeType = nullptr; + Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType(); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) { + ComputeType = nullptr; + Type = S.getASTContext().BoolTy; + ExpectedLoc = Tok; +} + class ResultBuilder::ShadowMapEntry::iterator { llvm::PointerUnion<const NamedDecl *, const DeclIndexPair *> DeclOrIterator; unsigned SingleDeclIndex; @@ -681,7 +876,8 @@ QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) { T = Property->getType(); else if (const auto *Value = dyn_cast<ValueDecl>(ND)) T = Value->getType(); - else + + if (T.isNull()) return QualType(); // Dig through references, function pointers, and block pointers to @@ -792,8 +988,8 @@ void ResultBuilder::AdjustResultPriorityForDecl(Result &R) { } } -DeclContext::lookup_result getConstructors(ASTContext &Context, - const CXXRecordDecl *Record) { +static DeclContext::lookup_result getConstructors(ASTContext &Context, + const CXXRecordDecl *Record) { QualType RecordTy = Context.getTypeDeclType(Record); DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( @@ -1028,7 +1224,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (HasObjectTypeQualifiers) if (const auto *Method = dyn_cast<CXXMethodDecl>(R.Declaration)) if (Method->isInstance()) { - Qualifiers MethodQuals = Method->getTypeQualifiers(); + Qualifiers MethodQuals = Method->getMethodQualifiers(); if (ObjectTypeQualifiers == MethodQuals) R.Priority += CCD_ObjectQualifierMatch; else if (ObjectTypeQualifiers - MethodQuals) { @@ -1727,6 +1923,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddPlaceholderChunk("name"); Builder.AddChunk(CodeCompletionString::CK_Equal); Builder.AddPlaceholderChunk("namespace"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // Using directives @@ -1735,6 +1932,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddTextChunk("namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("identifier"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // asm(string-literal) @@ -1769,6 +1967,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddPlaceholderChunk("qualifier"); Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // using typename qualifier::name (only in a dependent context) @@ -1780,6 +1979,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddPlaceholderChunk("qualifier"); Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } @@ -1969,12 +2169,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, if (S->getContinueParent()) { // continue ; Builder.AddTypedTextChunk("continue"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } if (S->getBreakParent()) { // break ; Builder.AddTypedTextChunk("break"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } @@ -1993,12 +2195,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); } + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // goto identifier ; Builder.AddTypedTextChunk("goto"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("label"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); // Using directives @@ -2007,6 +2211,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddTextChunk("namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("identifier"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts()); @@ -2409,6 +2614,11 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, bool SuppressName = false, bool SuppressBlock = false, Optional<ArrayRef<QualType>> ObjCSubsts = None) { + // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid. + // It would be better to pass in the param Type, which is usually avaliable. + // But this case is rare, so just pretend we fell back to int as elsewhere. + if (!Param) + return "int"; bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -2736,23 +2946,23 @@ static void AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, const FunctionDecl *Function) { const auto *Proto = Function->getType()->getAs<FunctionProtoType>(); - if (!Proto || !Proto->getTypeQuals()) + if (!Proto || !Proto->getMethodQuals()) return; // FIXME: Add ref-qualifier! // Handle single qualifiers without copying - if (Proto->getTypeQuals().hasOnlyConst()) { + if (Proto->getMethodQuals().hasOnlyConst()) { Result.AddInformativeChunk(" const"); return; } - if (Proto->getTypeQuals().hasOnlyVolatile()) { + if (Proto->getMethodQuals().hasOnlyVolatile()) { Result.AddInformativeChunk(" volatile"); return; } - if (Proto->getTypeQuals().hasOnlyRestrict()) { + if (Proto->getMethodQuals().hasOnlyRestrict()) { Result.AddInformativeChunk(" restrict"); return; } @@ -3856,13 +4066,15 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, } struct Sema::CodeCompleteExpressionData { - CodeCompleteExpressionData(QualType PreferredType = QualType()) + CodeCompleteExpressionData(QualType PreferredType = QualType(), + bool IsParenthesized = false) : PreferredType(PreferredType), IntegralConstantExpression(false), - ObjCCollection(false) {} + ObjCCollection(false), IsParenthesized(IsParenthesized) {} QualType PreferredType; bool IntegralConstantExpression; bool ObjCCollection; + bool IsParenthesized; SmallVector<Decl *, 4> IgnoreDecls; }; @@ -3873,13 +4085,18 @@ void Sema::CodeCompleteExpression(Scope *S, ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext(CodeCompletionContext::CCC_Expression, - Data.PreferredType)); + CodeCompletionContext( + Data.IsParenthesized + ? CodeCompletionContext::CCC_ParenthesizedExpression + : CodeCompletionContext::CCC_Expression, + Data.PreferredType)); + auto PCC = + Data.IsParenthesized ? PCC_ParenthesizedExpression : PCC_Expression; if (Data.ObjCCollection) Results.setFilter(&ResultBuilder::IsObjCCollection); else if (Data.IntegralConstantExpression) Results.setFilter(&ResultBuilder::IsIntegralConstantValue); - else if (WantTypesInContext(PCC_Expression, getLangOpts())) + else if (WantTypesInContext(PCC, getLangOpts())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); @@ -3897,7 +4114,7 @@ void Sema::CodeCompleteExpression(Scope *S, CodeCompleter->loadExternal()); Results.EnterNewScope(); - AddOrdinaryNameResults(PCC_Expression, S, *this, Results); + AddOrdinaryNameResults(PCC, S, *this, Results); Results.ExitScope(); bool PreferredTypeIsPointer = false; @@ -3917,13 +4134,16 @@ void Sema::CodeCompleteExpression(Scope *S, Results.data(), Results.size()); } -void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType) { - return CodeCompleteExpression(S, CodeCompleteExpressionData(PreferredType)); +void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType, + bool IsParenthesized) { + return CodeCompleteExpression( + S, CodeCompleteExpressionData(PreferredType, IsParenthesized)); } -void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { +void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, + QualType PreferredType) { if (E.isInvalid()) - CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction); + CodeCompleteExpression(S, PreferredType); else if (getLangOpts().ObjC) CodeCompleteObjCInstanceMessage(S, E.get(), None, false); } @@ -4211,7 +4431,8 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, - bool IsBaseExprStatement) { + bool IsBaseExprStatement, + QualType PreferredType) { if (!Base || !CodeCompleter) return; @@ -4239,6 +4460,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, } CodeCompletionContext CCContext(contextKind, ConvertedBaseType); + CCContext.setPreferredType(PreferredType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); @@ -4576,22 +4798,19 @@ typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; static void mergeCandidatesWithResults( Sema &SemaRef, SmallVectorImpl<ResultCandidate> &Results, OverloadCandidateSet &CandidateSet, SourceLocation Loc) { - if (!CandidateSet.empty()) { - // Sort the overload candidate set by placing the best overloads first. - std::stable_sort( - CandidateSet.begin(), CandidateSet.end(), - [&](const OverloadCandidate &X, const OverloadCandidate &Y) { - return isBetterOverloadCandidate(SemaRef, X, Y, Loc, - CandidateSet.getKind()); - }); - - // Add the remaining viable overload candidates as code-completion results. - for (OverloadCandidate &Candidate : CandidateSet) { - if (Candidate.Function && Candidate.Function->isDeleted()) - continue; - if (Candidate.Viable) - Results.push_back(ResultCandidate(Candidate.Function)); - } + // Sort the overload candidate set by placing the best overloads first. + llvm::stable_sort(CandidateSet, [&](const OverloadCandidate &X, + const OverloadCandidate &Y) { + return isBetterOverloadCandidate(SemaRef, X, Y, Loc, + CandidateSet.getKind()); + }); + + // Add the remaining viable overload candidates as code-completion results. + for (OverloadCandidate &Candidate : CandidateSet) { + if (Candidate.Function && Candidate.Function->isDeleted()) + continue; + if (Candidate.Viable) + Results.push_back(ResultCandidate(Candidate.Function)); } } @@ -4800,22 +5019,6 @@ void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { CodeCompleteExpression(S, Data); } -void Sema::CodeCompleteReturn(Scope *S) { - QualType ResultType; - if (isa<BlockDecl>(CurContext)) { - if (BlockScopeInfo *BSI = getCurBlock()) - ResultType = BSI->ReturnType; - } else if (const auto *Function = dyn_cast<FunctionDecl>(CurContext)) - ResultType = Function->getReturnType(); - else if (const auto *Method = dyn_cast<ObjCMethodDecl>(CurContext)) - ResultType = Method->getReturnType(); - - if (ResultType.isNull()) - CodeCompleteOrdinaryName(S, PCC_Expression); - else - CodeCompleteExpression(S, ResultType); -} - void Sema::CodeCompleteAfterIf(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), @@ -4877,91 +5080,6 @@ void Sema::CodeCompleteAfterIf(Scope *S) { Results.data(), Results.size()); } -static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS, - tok::TokenKind Op) { - if (!LHS) - return QualType(); - - QualType LHSType = LHS->getType(); - if (LHSType->isPointerType()) { - if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal) - return S.getASTContext().getPointerDiffType(); - // Pointer difference is more common than subtracting an int from a pointer. - if (Op == tok::minus) - return LHSType; - } - - switch (Op) { - // No way to infer the type of RHS from LHS. - case tok::comma: - return QualType(); - // Prefer the type of the left operand for all of these. - // Arithmetic operations. - case tok::plus: - case tok::plusequal: - case tok::minus: - case tok::minusequal: - case tok::percent: - case tok::percentequal: - case tok::slash: - case tok::slashequal: - case tok::star: - case tok::starequal: - // Assignment. - case tok::equal: - // Comparison operators. - case tok::equalequal: - case tok::exclaimequal: - case tok::less: - case tok::lessequal: - case tok::greater: - case tok::greaterequal: - case tok::spaceship: - return LHS->getType(); - // Binary shifts are often overloaded, so don't try to guess those. - case tok::greatergreater: - case tok::greatergreaterequal: - case tok::lessless: - case tok::lesslessequal: - if (LHSType->isIntegralOrEnumerationType()) - return S.getASTContext().IntTy; - return QualType(); - // Logical operators, assume we want bool. - case tok::ampamp: - case tok::pipepipe: - case tok::caretcaret: - return S.getASTContext().BoolTy; - // Operators often used for bit manipulation are typically used with the type - // of the left argument. - case tok::pipe: - case tok::pipeequal: - case tok::caret: - case tok::caretequal: - case tok::amp: - case tok::ampequal: - if (LHSType->isIntegralOrEnumerationType()) - return LHSType; - return QualType(); - // RHS should be a pointer to a member of the 'LHS' type, but we can't give - // any particular type here. - case tok::periodstar: - case tok::arrowstar: - return QualType(); - default: - // FIXME(ibiryukov): handle the missing op, re-add the assertion. - // assert(false && "unhandled binary op"); - return QualType(); - } -} - -void Sema::CodeCompleteBinaryRHS(Scope *S, Expr *LHS, tok::TokenKind Op) { - auto PreferredType = getPreferredTypeOfBinaryRHS(*this, LHS, Op); - if (!PreferredType.isNull()) - CodeCompleteExpression(S, PreferredType); - else - CodeCompleteOrdinaryName(S, PCC_Expression); -} - void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext, QualType BaseType) { if (SS.isEmpty() || !CodeCompleter) @@ -4974,7 +5092,20 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, if (SS.isInvalid()) { CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol); CC.setCXXScopeSpecifier(SS); - HandleCodeCompleteResults(this, CodeCompleter, CC, nullptr, 0); + // As SS is invalid, we try to collect accessible contexts from the current + // scope with a dummy lookup so that the completion consumer can try to + // guess what the specified scope is. + ResultBuilder DummyResults(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), CC); + if (S->getEntity()) { + CodeCompletionDeclConsumer Consumer(DummyResults, S->getEntity(), + BaseType); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + /*IncludeGlobalScope=*/false, + /*LoadExternal=*/false); + } + HandleCodeCompleteResults(this, CodeCompleter, + DummyResults.getCompletionContext(), nullptr, 0); return; } // Always pretend to enter a context to ensure that a dependent type @@ -6287,8 +6418,9 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, SourceLocation TemplateKWLoc; UnqualifiedId id; id.setIdentifier(Super, SuperLoc); - ExprResult SuperExpr = - ActOnIdExpression(S, SS, TemplateKWLoc, id, false, false); + ExprResult SuperExpr = ActOnIdExpression(S, SS, TemplateKWLoc, id, + /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(), SelIdents, AtArgumentExpression); } @@ -8258,7 +8390,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { // We need the native slashes for the actual file system interactions. SmallString<128> NativeRelDir = StringRef(RelDir); llvm::sys::path::native(NativeRelDir); - auto FS = getSourceManager().getFileManager().getVirtualFileSystem(); + llvm::vfs::FileSystem &FS = + getSourceManager().getFileManager().getVirtualFileSystem(); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), @@ -8284,20 +8417,39 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { }; // Helper: scans IncludeDir for nice files, and adds results for each. - auto AddFilesFromIncludeDir = [&](StringRef IncludeDir, bool IsSystem) { + auto AddFilesFromIncludeDir = [&](StringRef IncludeDir, + bool IsSystem, + DirectoryLookup::LookupType_t LookupType) { llvm::SmallString<128> Dir = IncludeDir; - if (!NativeRelDir.empty()) - llvm::sys::path::append(Dir, NativeRelDir); + if (!NativeRelDir.empty()) { + if (LookupType == DirectoryLookup::LT_Framework) { + // For a framework dir, #include <Foo/Bar/> actually maps to + // a path of Foo.framework/Headers/Bar/. + auto Begin = llvm::sys::path::begin(NativeRelDir); + auto End = llvm::sys::path::end(NativeRelDir); + + llvm::sys::path::append(Dir, *Begin + ".framework", "Headers"); + llvm::sys::path::append(Dir, ++Begin, End); + } else { + llvm::sys::path::append(Dir, NativeRelDir); + } + } std::error_code EC; unsigned Count = 0; - for (auto It = FS->dir_begin(Dir, EC); + for (auto It = FS.dir_begin(Dir, EC); !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) { if (++Count == 2500) // If we happen to hit a huge directory, break; // bail out early so we're not too slow. StringRef Filename = llvm::sys::path::filename(It->path()); switch (It->type()) { case llvm::sys::fs::file_type::directory_file: + // All entries in a framework directory must have a ".framework" suffix, + // but the suffix does not appear in the source code's include/import. + if (LookupType == DirectoryLookup::LT_Framework && + NativeRelDir.empty() && !Filename.consume_back(".framework")) + break; + AddCompletion(Filename, /*IsDirectory=*/true); break; case llvm::sys::fs::file_type::regular_file: @@ -8326,10 +8478,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { // header maps are not (currently) enumerable. break; case DirectoryLookup::LT_NormalDir: - AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem); + AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem, + DirectoryLookup::LT_NormalDir); break; case DirectoryLookup::LT_Framework: - AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem); + AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem, + DirectoryLookup::LT_Framework); break; } }; @@ -8343,7 +8497,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { // The current directory is on the include path for "quoted" includes. auto *CurFile = PP.getCurrentFileLexer()->getFileEntry(); if (CurFile && CurFile->getDir()) - AddFilesFromIncludeDir(CurFile->getDir()->getName(), false); + AddFilesFromIncludeDir(CurFile->getDir()->getName(), false, + DirectoryLookup::LT_NormalDir); for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end())) AddFilesFromDirLookup(D, false); } diff --git a/lib/Sema/SemaConsumer.cpp b/lib/Sema/SemaConsumer.cpp index d83a13e2f1..02623be00c 100644 --- a/lib/Sema/SemaConsumer.cpp +++ b/lib/Sema/SemaConsumer.cpp @@ -1,9 +1,8 @@ //===-- SemaConsumer.cpp - Abstract interface for AST semantics -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index 181efa6d3d..9d328f4926 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -1,9 +1,8 @@ -//===--- SemaCoroutines.cpp - Semantic Analysis for Coroutines ------------===// +//===-- SemaCoroutine.cpp - Semantic Analysis for Coroutines --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -186,21 +185,8 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, static bool isValidCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { - // 'co_await' and 'co_yield' are not permitted in unevaluated operands, - // such as subexpressions of \c sizeof. - // - // [expr.await]p2, emphasis added: "An await-expression shall appear only in - // a *potentially evaluated* expression within the compound-statement of a - // function-body outside of a handler [...] A context within a function where - // an await-expression can appear is called a suspension context of the - // function." And per [expr.yield]p1: "A yield-expression shall appear only - // within a suspension context of a function." - if (S.isUnevaluatedContext()) { - S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; - return false; - } - - // Per [expr.await]p2, any other usage must be within a function. + // [expr.await]p2 dictates that 'co_await' and 'co_yield' must be used within + // a function body. // FIXME: This also covers [expr.await]p2: "An await-expression shall not // appear in a default argument." But the diagnostic QoI here could be // improved to inform the user that default arguments specifically are not @@ -669,12 +655,57 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, return true; } +// Recursively walks up the scope hierarchy until either a 'catch' or a function +// scope is found, whichever comes first. +static bool isWithinCatchScope(Scope *S) { + // 'co_await' and 'co_yield' keywords are disallowed within catch blocks, but + // lambdas that use 'co_await' are allowed. The loop below ends when a + // function scope is found in order to ensure the following behavior: + // + // void foo() { // <- function scope + // try { // + // co_await x; // <- 'co_await' is OK within a function scope + // } catch { // <- catch scope + // co_await x; // <- 'co_await' is not OK within a catch scope + // []() { // <- function scope + // co_await x; // <- 'co_await' is OK within a function scope + // }(); + // } + // } + while (S && !(S->getFlags() & Scope::FnScope)) { + if (S->getFlags() & Scope::CatchScope) + return true; + S = S->getParent(); + } + return false; +} + +// [expr.await]p2, emphasis added: "An await-expression shall appear only in +// a *potentially evaluated* expression within the compound-statement of a +// function-body *outside of a handler* [...] A context within a function +// where an await-expression can appear is called a suspension context of the +// function." +static void checkSuspensionContext(Sema &S, SourceLocation Loc, + StringRef Keyword) { + // First emphasis of [expr.await]p2: must be a potentially evaluated context. + // That is, 'co_await' and 'co_yield' cannot appear in subexpressions of + // \c sizeof. + if (S.isUnevaluatedContext()) + S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; + + // Second emphasis of [expr.await]p2: must be outside of an exception handler. + if (isWithinCatchScope(S.getCurScope())) + S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword; +} + ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) { CorrectDelayedTyposInExpr(E); return ExprError(); } + checkSuspensionContext(*this, Loc, "co_await"); + if (E->getType()->isPlaceholderType()) { ExprResult R = CheckPlaceholderExpr(E); if (R.isInvalid()) return ExprError(); @@ -772,6 +803,8 @@ ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { return ExprError(); } + checkSuspensionContext(*this, Loc, "co_yield"); + // Build yield_value call. ExprResult Awaitable = buildPromiseCall( *this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 23c99d45a7..379e2aefb4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1,9 +1,8 @@ //===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -62,7 +61,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { namespace { -class TypeNameValidatorCCC : public CorrectionCandidateCallback { +class TypeNameValidatorCCC final : public CorrectionCandidateCallback { public: TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false, bool AllowTemplates = false, @@ -106,6 +105,10 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback { return !WantClassName && candidate.isKeyword(); } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<TypeNameValidatorCCC>(*this); + } + private: bool AllowInvalidDecl; bool WantClassName; @@ -368,11 +371,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { - TypoCorrection Correction = - CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS, - llvm::make_unique<TypeNameValidatorCCC>( - true, isClassName, AllowDeducedTemplate), - CTK_ErrorRecovery); + TypeNameValidatorCCC CCC(/*AllowInvalid=*/true, isClassName, + AllowDeducedTemplate); + TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), Kind, + S, SS, CCC, CTK_ErrorRecovery); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; @@ -665,11 +667,12 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. + TypeNameValidatorCCC CCC(/*AllowInvalid=*/false, /*WantClass=*/false, + /*AllowTemplates=*/IsTemplateName, + /*AllowNonTemplates=*/!IsTemplateName); if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, - llvm::make_unique<TypeNameValidatorCCC>( - false, false, IsTemplateName, !IsTemplateName), - CTK_ErrorRecovery)) { + CCC, CTK_ErrorRecovery)) { // FIXME: Support error recovery for the template-name case. bool CanRecover = !IsTemplateName; if (Corrected.isKeyword()) { @@ -844,8 +847,7 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, - bool IsAddressOfOperand, - std::unique_ptr<CorrectionCandidateCallback> CCC) { + bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); @@ -927,10 +929,9 @@ Corrected: // close to this name. if (!SecondTry && CCC) { SecondTry = true; - if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), - Result.getLookupKind(), S, - &SS, std::move(CCC), - CTK_ErrorRecovery)) { + if (TypoCorrection Corrected = + CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, + &SS, *CCC, CTK_ErrorRecovery)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; @@ -1018,7 +1019,8 @@ Corrected: case LookupResult::Ambiguous: if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && - hasAnyAcceptableTemplateNames(Result)) { + hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true, + /*AllowDependent=*/false)) { // C++ [temp.local]p3: // A lookup that finds an injected-class-name (10.2) can result in an // ambiguity in certain cases (for example, if it is found in more than @@ -1042,7 +1044,9 @@ Corrected: } if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && - (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) { + (IsFilteredTemplateName || + hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true, + /*AllowDependent=*/false))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that // an operator-function-id or a literal- operator-id refers to a set of @@ -1061,15 +1065,16 @@ Corrected: Template = Context.getOverloadedTemplateName(Result.begin(), Result.end()); } else { - TemplateDecl *TD - = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl()); + auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl( + *Result.begin(), /*AllowFunctionTemplates=*/true, + /*AllowDependent=*/false)); IsFunctionTemplate = isa<FunctionTemplateDecl>(TD); IsVarTemplate = isa<VarTemplateDecl>(TD); if (SS.isSet() && !SS.isInvalid()) - Template = Context.getQualifiedTemplateName(SS.getScopeRep(), - /*TemplateKeyword=*/false, - TD); + Template = + Context.getQualifiedTemplateName(SS.getScopeRep(), + /*TemplateKeyword=*/false, TD); else Template = TemplateName(TD); } @@ -1399,11 +1404,6 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } } -void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { - if (IdResolver.tryAddTopLevelDecl(D, Name) && TUScope) - TUScope->AddDecl(D); -} - bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S, bool AllowInlineNamespace) { return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace); @@ -1461,12 +1461,17 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { Module *NewM = New->getOwningModule(); Module *OldM = Old->getOwningModule(); + + if (NewM && NewM->Kind == Module::PrivateModuleFragment) + NewM = NewM->Parent; + if (OldM && OldM->Kind == Module::PrivateModuleFragment) + OldM = OldM->Parent; + if (NewM == OldM) return false; - // FIXME: Check proclaimed-ownership-declarations here too. - bool NewIsModuleInterface = NewM && NewM->Kind == Module::ModuleInterfaceUnit; - bool OldIsModuleInterface = OldM && OldM->Kind == Module::ModuleInterfaceUnit; + bool NewIsModuleInterface = NewM && NewM->isModulePurview(); + bool OldIsModuleInterface = OldM && OldM->isModulePurview(); if (NewIsModuleInterface || OldIsModuleInterface) { // C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]: // if a declaration of D [...] appears in the purview of a module, all @@ -1862,10 +1867,10 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, if (!IDecl && DoTypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. - if (TypoCorrection C = CorrectTypo( - DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, nullptr, - llvm::make_unique<DeclFilterCCC<ObjCInterfaceDecl>>(), - CTK_ErrorRecovery)) { + DeclFilterCCC<ObjCInterfaceDecl> CCC{}; + if (TypoCorrection C = + CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, + TUScope, nullptr, CCC, CTK_ErrorRecovery)) { diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id); IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>(); Id = IDecl->getIdentifier(); @@ -1927,10 +1932,13 @@ static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S, Context.setObjCSuperType(Context.getTagDeclType(TD)); } -static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) { +static StringRef getHeaderName(Builtin::Context &BuiltinInfo, unsigned ID, + ASTContext::GetBuiltinTypeError Error) { switch (Error) { case ASTContext::GE_None: return ""; + case ASTContext::GE_Missing_type: + return BuiltinInfo.getHeaderName(ID); case ASTContext::GE_Missing_stdio: return "stdio.h"; case ASTContext::GE_Missing_setjmp: @@ -1955,7 +1963,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, if (Error) { if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_sysheader) - << getHeaderName(Error) << Context.BuiltinInfo.getName(ID); + << getHeaderName(Context.BuiltinInfo, ID, Error) + << Context.BuiltinInfo.getName(ID); return nullptr; } @@ -2427,13 +2436,11 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *NewAttr = nullptr; unsigned AttrSpellingListIndex = Attr->getSpellingListIndex(); if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr)) - NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(), - AA->isImplicit(), AA->getIntroduced(), - AA->getDeprecated(), - AA->getObsoleted(), AA->getUnavailable(), - AA->getMessage(), AA->getStrict(), - AA->getReplacement(), AMK, - AttrSpellingListIndex); + NewAttr = S.mergeAvailabilityAttr( + D, AA->getRange(), AA->getPlatform(), AA->isImplicit(), + AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(), + AA->getUnavailable(), AA->getMessage(), AA->getStrict(), + AA->getReplacement(), AMK, AA->getPriority(), AttrSpellingListIndex); else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr)) NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), AttrSpellingListIndex); @@ -2489,6 +2496,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, else if (const auto *UA = dyn_cast<UuidAttr>(Attr)) NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex, UA->getGuid()); + else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr)) + NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA); + else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr)) + NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA); else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr)) NewAttr = cast<InheritableAttr>(Attr->clone(S.Context)); @@ -2926,7 +2937,8 @@ static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A, const auto *AttrB = B->getAttr<PassObjectSizeAttr>(); if (AttrA == AttrB) return true; - return AttrA && AttrB && AttrA->getType() == AttrB->getType(); + return AttrA && AttrB && AttrA->getType() == AttrB->getType() && + AttrA->isDynamic() == AttrB->isDynamic(); }; return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq); @@ -3126,6 +3138,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // there but not here. NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; + } else if (New->getBuiltinID()) { + // Calling Conventions on a Builtin aren't really useful and setting a + // default calling convention and cdecl'ing some builtin redeclarations is + // common, so warn and ignore the calling convention on the redeclaration. + Diag(New->getLocation(), diag::warn_cconv_ignored) + << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) + << (int)CallingConventionIgnoredReason::BuiltinFunction; + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; } else { // Calling conventions aren't compatible, so complain. bool FirstCCExplicit = getCallingConvAttributedType(First->getType()); @@ -4796,6 +4817,18 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; } + // C++ [dcl.dcl]p3: + // [If there are no declarators], and except for the declaration of an + // unnamed bit-field, the decl-specifier-seq shall introduce one or more + // names into the program + // C++ [class.mem]p2: + // each such member-declaration shall either declare at least one member + // name of the class or declare at least one unnamed bit-field + // + // For C this is an error even for a named struct, and is diagnosed elsewhere. + if (getLangOpts().CPlusPlus && Record->field_empty()) + Diag(DS.getBeginLoc(), diag::ext_no_declarators) << DS.getSourceRange(); + // Mock up a declarator. Declarator Dc(DS, DeclaratorContext::MemberContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); @@ -5082,7 +5115,7 @@ static bool hasSimilarParameters(ASTContext &Context, QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); // The parameter types are identical - if (Context.hasSameType(DefParamTy, DeclParamTy)) + if (Context.hasSameUnqualifiedType(DefParamTy, DeclParamTy)) continue; QualType DeclParamBaseTy = getCoreType(DeclParamTy); @@ -5955,10 +5988,24 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } if (const InheritableAttr *Attr = getDLLAttr(&ND)) { + auto *VD = dyn_cast<VarDecl>(&ND); + bool IsAnonymousNS = false; + bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft(); + if (VD) { + const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(VD->getDeclContext()); + while (NS && !IsAnonymousNS) { + IsAnonymousNS = NS->isAnonymousNamespace(); + NS = dyn_cast<NamespaceDecl>(NS->getParent()); + } + } // dll attributes require external linkage. Static locals may have external // linkage but still cannot be explicitly imported or exported. - auto *VD = dyn_cast<VarDecl>(&ND); - if (!ND.isExternallyVisible() || (VD && VD->isStaticLocal())) { + // In Microsoft mode, a variable defined in anonymous namespace must have + // external linkage in order to be exported. + bool AnonNSInMicrosoftMode = IsAnonymousNS && IsMicrosoft; + if ((ND.isExternallyVisible() && AnonNSInMicrosoftMode) || + (!AnonNSInMicrosoftMode && + (!ND.isExternallyVisible() || (VD && VD->isStaticLocal())))) { S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern) << &ND << Attr; ND.setInvalidDecl(); @@ -6187,7 +6234,8 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) { static bool shouldConsiderLinkage(const VarDecl *VD) { const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); - if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC)) + if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC) || + isa<OMPDeclareMapperDecl>(DC)) return VD->hasExternalStorage(); if (DC->isFileContext()) return true; @@ -6199,7 +6247,7 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { static bool shouldConsiderLinkage(const FunctionDecl *FD) { const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); if (DC->isFileContext() || DC->isFunctionOrMethod() || - isa<OMPDeclareReductionDecl>(DC)) + isa<OMPDeclareReductionDecl>(DC) || isa<OMPDeclareMapperDecl>(DC)) return true; if (DC->isRecord()) return false; @@ -7654,7 +7702,7 @@ namespace { // Callback to only accept typo corrections that have a non-zero edit distance. // Also only accept corrections that have the same parent decl. -class DifferentNameValidatorCCC : public CorrectionCandidateCallback { +class DifferentNameValidatorCCC final : public CorrectionCandidateCallback { public: DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD, CXXRecordDecl *Parent) @@ -7686,6 +7734,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback { return false; } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<DifferentNameValidatorCCC>(*this); + } + private: ASTContext &Context; FunctionDecl *OriginalFD; @@ -7733,6 +7785,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration( assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); + DifferentNameValidatorCCC CCC(SemaRef.Context, NewFD, + MD ? MD->getParent() : nullptr); if (!Prev.empty()) { for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { @@ -7749,10 +7803,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration( // If the qualified name lookup yielded nothing, try typo correction } else if ((Correction = SemaRef.CorrectTypo( Prev.getLookupNameInfo(), Prev.getLookupKind(), S, - &ExtraArgs.D.getCXXScopeSpec(), - llvm::make_unique<DifferentNameValidatorCCC>( - SemaRef.Context, NewFD, MD ? MD->getParent() : nullptr), - Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) { + &ExtraArgs.D.getCXXScopeSpec(), CCC, Sema::CTK_ErrorRecovery, + IsLocalFriend ? nullptr : NewDC))) { // Set up everything for the call to ActOnFunctionDeclarator ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); @@ -8044,8 +8096,7 @@ static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) { QualType DesugaredTy = Ty; do { ArrayRef<StringRef> Names(SizeTypeNames); - auto Match = - std::find(Names.begin(), Names.end(), DesugaredTy.getAsString()); + auto Match = llvm::find(Names, DesugaredTy.getAsString()); if (Names.end() != Match) return true; @@ -8620,8 +8671,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Complain about the 'static' specifier if it's on an out-of-line // member function definition. + + // MSVC permits the use of a 'static' storage specifier on an out-of-line + // member function template declaration, warn about this. Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_out_of_line) + NewFD->getDescribedFunctionTemplate() && getLangOpts().MSVCCompat + ? diag::ext_static_out_of_line : diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } @@ -9031,8 +9086,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // nothing will diagnose that error later. if (isFriend && (D.getCXXScopeSpec().getScopeRep()->isDependent() || - (!Previous.empty() && (TemplateParamLists.size() || - CurContext->isDependentContext())))) { + (!Previous.empty() && CurContext->isDependentContext()))) { // ignore these } else { // The user tried to provide an out-of-line definition for a @@ -9137,13 +9191,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().CUDA) { IdentifierInfo *II = NewFD->getIdentifier(); - if (II && - II->isStr(getLangOpts().HIP ? "hipConfigureCall" - : "cudaConfigureCall") && + if (II && II->isStr(getCudaConfigureFuncName()) && !NewFD->isInvalidDecl() && NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (!R->getAs<FunctionType>()->getReturnType()->isScalarType()) - Diag(NewFD->getLocation(), diag::err_config_scalar_return); + Diag(NewFD->getLocation(), diag::err_config_scalar_return) + << getCudaConfigureFuncName(); Context.setcudaConfigureCallDecl(NewFD); } @@ -9575,9 +9628,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, /// Returns true if there was an error, false otherwise. static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD, MultiVersionKind MVType, - const TargetAttr *TA, - const CPUDispatchAttr *CPUDisp, - const CPUSpecificAttr *CPUSpec) { + const TargetAttr *TA) { assert(MVType != MultiVersionKind::None && "Function lacks multiversion attribute"); @@ -9884,8 +9935,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // multiversioning, this isn't an error condition. if (MVType == MultiVersionKind::None) return false; - return CheckMultiVersionFirstFunction(S, NewFD, MVType, NewTA, NewCPUDisp, - NewCPUSpec); + return CheckMultiVersionFirstFunction(S, NewFD, MVType, NewTA); } FunctionDecl *OldFD = OldDecl->getAsFunction(); @@ -10017,7 +10067,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() && !MD->isStatic() && !isa<CXXConstructorDecl>(MD) && - !MD->getTypeQualifiers().hasConst()) { + !MD->getMethodQualifiers().hasConst()) { CXXMethodDecl *OldMD = nullptr; if (OldDecl) OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction()); @@ -10808,7 +10858,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, SourceRange Range, bool DirectInit, - Expr *&Init) { + Expr *Init) { bool IsInitCapture = !VDecl; assert((!VDecl || !VDecl->isInitCapture()) && "init captures are expected to be deduced prior to initialization"); @@ -10924,8 +10974,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, << (DeduceInit->getType().isNull() ? TSI->getType() : DeduceInit->getType()) << DeduceInit->getSourceRange(); - } else - Init = DeduceInit; + } // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using // 'id' instead of a specific object type prevents most of our usual @@ -10942,7 +10991,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, } bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, - Expr *&Init) { + Expr *Init) { QualType DeducedType = deduceVarTypeFromInitializer( VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init); @@ -11244,6 +11293,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { << Culprit->getSourceRange(); } } + + if (auto *E = dyn_cast<ExprWithCleanups>(Init)) + if (auto *BE = dyn_cast<BlockExpr>(E->getSubExpr()->IgnoreParens())) + if (VDecl->hasLocalStorage()) + BE->getBlockDecl()->setCanAvoidCopyToHeap(); } else if (VDecl->isStaticDataMember() && !VDecl->isInline() && VDecl->getLexicalDeclContext()->isRecord()) { // This is an in-class initialization for a static data member, e.g., @@ -11358,6 +11412,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { !isTemplateInstantiation(VDecl->getTemplateSpecializationKind())) Diag(VDecl->getLocation(), diag::warn_extern_init); + // In Microsoft C++ mode, a const variable defined in namespace scope has + // external linkage by default if the variable is declared with + // __declspec(dllexport). + if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + getLangOpts().CPlusPlus && VDecl->getType().isConstQualified() && + VDecl->hasAttr<DLLExportAttr>() && VDecl->getDefinition()) + VDecl->setStorageClass(SC_Extern); + // C99 6.7.8p4. All file scoped initializers need to be constant. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) CheckForConstantInitializer(Init, DclT); @@ -11448,9 +11510,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { return; } - Expr *TmpInit = nullptr; if (Type->isUndeducedType() && - DeduceVariableDeclarationType(Var, false, TmpInit)) + DeduceVariableDeclarationType(Var, false, nullptr)) return; // C++11 [class.static.data]p3: A static data member can be declared with @@ -11627,7 +11688,11 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { setFunctionHasBranchProtectedScope(); } } - + // In OpenCL, we can't initialize objects in the __local address space, + // even implicitly, so don't synthesize an implicit initializer. + if (getLangOpts().OpenCL && + Var->getType().getAddressSpace() == LangAS::opencl_local) + return; // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the // object is of (possibly cv-qualified) non-POD class type (or @@ -11723,7 +11788,6 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, D.SetIdentifier(Ident, IdentLoc); D.takeAttributes(Attrs, AttrEnd); - ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory()); D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/ false), IdentLoc); Decl *Var = ActOnDeclarator(S, D); @@ -12538,9 +12602,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // - otherwise, it's an error if (T->isArrayType()) { if (!T.isConstQualified()) { - DelayedDiagnostics.add( - sema::DelayedDiagnostic::makeForbiddenType( - NameLoc, diag::err_arc_array_param_no_ownership, T, false)); + if (DelayedDiagnostics.shouldDelayDiagnostics()) + DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType( + NameLoc, diag::err_arc_array_param_no_ownership, T, false)); + else + Diag(NameLoc, diag::err_arc_array_param_no_ownership) + << TSInfo->getTypeLoc().getSourceRange(); } lifetime = Qualifiers::OCL_ExplicitNone; } else { @@ -13092,6 +13160,35 @@ private: bool IsLambda = false; }; +static void diagnoseImplicitlyRetainedSelf(Sema &S) { + llvm::DenseMap<const BlockDecl *, bool> EscapeInfo; + + auto IsOrNestedInEscapingBlock = [&](const BlockDecl *BD) { + if (EscapeInfo.count(BD)) + return EscapeInfo[BD]; + + bool R = false; + const BlockDecl *CurBD = BD; + + do { + R = !CurBD->doesNotEscape(); + if (R) + break; + CurBD = CurBD->getParent()->getInnermostBlockDecl(); + } while (CurBD); + + return EscapeInfo[BD] = R; + }; + + // If the location where 'self' is implicitly retained is inside a escaping + // block, emit a diagnostic. + for (const std::pair<SourceLocation, const BlockDecl *> &P : + S.ImplicitlyRetainedSelfLocs) + if (IsOrNestedInEscapingBlock(P.second)) + S.Diag(P.first, diag::warn_implicitly_retains_self) + << FixItHint::CreateInsertion(P.first, "self->"); +} + Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation) { FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr; @@ -13099,7 +13196,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine()) + if (getLangOpts().Coroutines && getCurFunction()->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); // Do not call PopExpressionEvaluationContext() if it is a lambda because one @@ -13156,7 +13253,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // MSVC permits the use of pure specifier (=0) on function definition, // defined at class scope, warn about this non-standard construct. - if (getLangOpts().MicrosoftExt && FD->isPure() && FD->isCanonicalDecl()) + if (getLangOpts().MicrosoftExt && FD->isPure() && !FD->isOutOfLine()) Diag(FD->getLocation(), diag::ext_pure_function_definition); if (!FD->isInvalidDecl()) { @@ -13256,8 +13353,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); if (!MD->isInvalidDecl()) { - if (!MD->hasSkippedBody()) - DiagnoseUnusedParameters(MD->parameters()); DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), MD->getReturnType(), MD); @@ -13303,6 +13398,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, diag::warn_objc_secondary_init_missing_init_call); getCurFunction()->ObjCWarnForNoInitDelegation = false; } + + diagnoseImplicitlyRetainedSelf(*this); } else { // Parsing the function declaration failed in some way. Pop the fake scope // we pushed on. @@ -13484,10 +13581,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // function declaration is going to be treated as an error. if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { TypoCorrection Corrected; - if (S && - (Corrected = CorrectTypo( - DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, nullptr, - llvm::make_unique<DeclFilterCCC<FunctionDecl>>(), CTK_NonError))) + DeclFilterCCC<FunctionDecl> CCC{}; + if (S && (Corrected = + CorrectTypo(DeclarationNameInfo(&II, Loc), LookupOrdinaryName, + S, nullptr, CCC, CTK_NonError))) diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion), /*ErrorRecovery*/false); } @@ -13576,6 +13673,13 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->getLocation())); } + // Handle automatically recognized callbacks. + SmallVector<int, 4> Encoding; + if (!FD->hasAttr<CallbackAttr>() && + Context.BuiltinInfo.performsCallback(BuiltinID, Encoding)) + FD->addAttr(CallbackAttr::CreateImplicit( + Context, Encoding.data(), Encoding.size(), FD->getLocation())); + // Mark const if we don't care about errno and that is the only thing // preventing the function from being const. This allows IRgen to use LLVM // intrinsics for such functions. @@ -14743,8 +14847,7 @@ CreateNewDecl: // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; - if (IsFixed && (getLangOpts().CPlusPlus11 || getLangOpts().ObjC) && - cast<EnumDecl>(New)->isFixed()) { + if (IsFixed && cast<EnumDecl>(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. // Conflicts are diagnosed above. Do nothing. } @@ -15897,6 +16000,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasObjectMember(true); if (Record && FDTTy->getDecl()->hasVolatileMember()) Record->setHasVolatileMember(true); + if (Record && Record->isUnion() && + FD->getType().isNonTrivialPrimitiveCType(Context)) + Diag(FD->getLocation(), + diag::err_nontrivial_primitive_type_in_union); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object) @@ -15904,7 +16011,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && - Record && !ObjCFieldLifetimeErrReported && Record->isUnion()) { + Record && !ObjCFieldLifetimeErrReported && Record->isUnion() && + !getLangOpts().CPlusPlus) { // It's an error in ARC or Weak if a field has lifetime. // We don't want to report this in a system header, though, // so we just make the field unavailable. @@ -16907,390 +17015,6 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, return New; } -static void checkModuleImportContext(Sema &S, Module *M, - SourceLocation ImportLoc, DeclContext *DC, - bool FromInclude = false) { - SourceLocation ExternCLoc; - - if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) { - switch (LSD->getLanguage()) { - case LinkageSpecDecl::lang_c: - if (ExternCLoc.isInvalid()) - ExternCLoc = LSD->getBeginLoc(); - break; - case LinkageSpecDecl::lang_cxx: - break; - } - DC = LSD->getParent(); - } - - while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC)) - DC = DC->getParent(); - - if (!isa<TranslationUnitDecl>(DC)) { - S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M)) - ? diag::ext_module_import_not_at_top_level_noop - : diag::err_module_import_not_at_top_level_fatal) - << M->getFullModuleName() << DC; - S.Diag(cast<Decl>(DC)->getBeginLoc(), - diag::note_module_import_not_at_top_level) - << DC; - } else if (!M->IsExternC && ExternCLoc.isValid()) { - S.Diag(ImportLoc, diag::ext_module_import_in_extern_c) - << M->getFullModuleName(); - S.Diag(ExternCLoc, diag::note_extern_c_begins_here); - } -} - -Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, - SourceLocation ModuleLoc, - ModuleDeclKind MDK, - ModuleIdPath Path) { - assert(getLangOpts().ModulesTS && - "should only have module decl in modules TS"); - - // A module implementation unit requires that we are not compiling a module - // of any kind. A module interface unit requires that we are not compiling a - // module map. - switch (getLangOpts().getCompilingModule()) { - case LangOptions::CMK_None: - // It's OK to compile a module interface as a normal translation unit. - break; - - case LangOptions::CMK_ModuleInterface: - if (MDK != ModuleDeclKind::Implementation) - break; - - // We were asked to compile a module interface unit but this is a module - // implementation unit. That indicates the 'export' is missing. - Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch) - << FixItHint::CreateInsertion(ModuleLoc, "export "); - MDK = ModuleDeclKind::Interface; - break; - - case LangOptions::CMK_ModuleMap: - Diag(ModuleLoc, diag::err_module_decl_in_module_map_module); - return nullptr; - - case LangOptions::CMK_HeaderModule: - Diag(ModuleLoc, diag::err_module_decl_in_header_module); - return nullptr; - } - - assert(ModuleScopes.size() == 1 && "expected to be at global module scope"); - - // FIXME: Most of this work should be done by the preprocessor rather than - // here, in order to support macro import. - - // Only one module-declaration is permitted per source file. - if (ModuleScopes.back().Module->Kind == Module::ModuleInterfaceUnit) { - Diag(ModuleLoc, diag::err_module_redeclaration); - Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module), - diag::note_prev_module_declaration); - return nullptr; - } - - // Flatten the dots in a module name. Unlike Clang's hierarchical module map - // modules, the dots here are just another character that can appear in a - // module name. - std::string ModuleName; - for (auto &Piece : Path) { - if (!ModuleName.empty()) - ModuleName += "."; - ModuleName += Piece.first->getName(); - } - - // If a module name was explicitly specified on the command line, it must be - // correct. - if (!getLangOpts().CurrentModule.empty() && - getLangOpts().CurrentModule != ModuleName) { - Diag(Path.front().second, diag::err_current_module_name_mismatch) - << SourceRange(Path.front().second, Path.back().second) - << getLangOpts().CurrentModule; - return nullptr; - } - const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; - - auto &Map = PP.getHeaderSearchInfo().getModuleMap(); - Module *Mod; - - switch (MDK) { - case ModuleDeclKind::Interface: { - // We can't have parsed or imported a definition of this module or parsed a - // module map defining it already. - if (auto *M = Map.findModule(ModuleName)) { - Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; - if (M->DefinitionLoc.isValid()) - Diag(M->DefinitionLoc, diag::note_prev_module_definition); - else if (const auto *FE = M->getASTFile()) - Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) - << FE->getName(); - Mod = M; - break; - } - - // Create a Module for the module that we're defining. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - ModuleScopes.front().Module); - assert(Mod && "module creation should not fail"); - break; - } - - case ModuleDeclKind::Partition: - // FIXME: Check we are in a submodule of the named module. - return nullptr; - - case ModuleDeclKind::Implementation: - std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( - PP.getIdentifierInfo(ModuleName), Path[0].second); - Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, - Module::AllVisible, - /*IsIncludeDirective=*/false); - if (!Mod) { - Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; - // Create an empty module interface unit for error recovery. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - ModuleScopes.front().Module); - } - break; - } - - // Switch from the global module to the named module. - ModuleScopes.back().Module = Mod; - ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation; - VisibleModules.setVisible(Mod, ModuleLoc); - - // From now on, we have an owning module for all declarations we see. - // However, those declarations are module-private unless explicitly - // exported. - auto *TU = Context.getTranslationUnitDecl(); - TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); - TU->setLocalOwningModule(Mod); - - // FIXME: Create a ModuleDecl. - return nullptr; -} - -DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, - SourceLocation ImportLoc, - ModuleIdPath Path) { - // Flatten the module path for a Modules TS module name. - std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc; - if (getLangOpts().ModulesTS) { - std::string ModuleName; - for (auto &Piece : Path) { - if (!ModuleName.empty()) - ModuleName += "."; - ModuleName += Piece.first->getName(); - } - ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; - Path = ModuleIdPath(ModuleNameLoc); - } - - Module *Mod = - getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, - /*IsIncludeDirective=*/false); - if (!Mod) - return true; - - VisibleModules.setVisible(Mod, ImportLoc); - - checkModuleImportContext(*this, Mod, ImportLoc, CurContext); - - // FIXME: we should support importing a submodule within a different submodule - // of the same top-level module. Until we do, make it an error rather than - // silently ignoring the import. - // Import-from-implementation is valid in the Modules TS. FIXME: Should we - // warn on a redundant import of the current module? - if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && - (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) - Diag(ImportLoc, getLangOpts().isCompilingModule() - ? diag::err_module_self_import - : diag::err_module_import_in_implementation) - << Mod->getFullModuleName() << getLangOpts().CurrentModule; - - SmallVector<SourceLocation, 2> IdentifierLocs; - Module *ModCheck = Mod; - for (unsigned I = 0, N = Path.size(); I != N; ++I) { - // If we've run out of module parents, just drop the remaining identifiers. - // We need the length to be consistent. - if (!ModCheck) - break; - ModCheck = ModCheck->Parent; - - IdentifierLocs.push_back(Path[I].second); - } - - ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc, - Mod, IdentifierLocs); - if (!ModuleScopes.empty()) - Context.addModuleInitializer(ModuleScopes.back().Module, Import); - CurContext->addDecl(Import); - - // Re-export the module if needed. - if (Import->isExported() && - !ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) - getCurrentModule()->Exports.emplace_back(Mod, false); - - return Import; -} - -void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { - checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); - BuildModuleInclude(DirectiveLoc, Mod); -} - -void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { - // Determine whether we're in the #include buffer for a module. The #includes - // in that buffer do not qualify as module imports; they're just an - // implementation detail of us building the module. - // - // FIXME: Should we even get ActOnModuleInclude calls for those? - bool IsInModuleIncludes = - TUKind == TU_Module && - getSourceManager().isWrittenInMainFile(DirectiveLoc); - - bool ShouldAddImport = !IsInModuleIncludes; - - // If this module import was due to an inclusion directive, create an - // implicit import declaration to capture it in the AST. - if (ShouldAddImport) { - TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); - ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, - DirectiveLoc, Mod, - DirectiveLoc); - if (!ModuleScopes.empty()) - Context.addModuleInitializer(ModuleScopes.back().Module, ImportD); - TU->addDecl(ImportD); - Consumer.HandleImplicitImportDecl(ImportD); - } - - getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc); - VisibleModules.setVisible(Mod, DirectiveLoc); -} - -void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { - checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); - - ModuleScopes.push_back({}); - ModuleScopes.back().Module = Mod; - if (getLangOpts().ModulesLocalVisibility) - ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); - - VisibleModules.setVisible(Mod, DirectiveLoc); - - // The enclosing context is now part of this module. - // FIXME: Consider creating a child DeclContext to hold the entities - // lexically within the module. - if (getLangOpts().trackLocalOwningModule()) { - for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) { - cast<Decl>(DC)->setModuleOwnershipKind( - getLangOpts().ModulesLocalVisibility - ? Decl::ModuleOwnershipKind::VisibleWhenImported - : Decl::ModuleOwnershipKind::Visible); - cast<Decl>(DC)->setLocalOwningModule(Mod); - } - } -} - -void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { - if (getLangOpts().ModulesLocalVisibility) { - VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules); - // Leaving a module hides namespace names, so our visible namespace cache - // is now out of date. - VisibleNamespaceCache.clear(); - } - - assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod && - "left the wrong module scope"); - ModuleScopes.pop_back(); - - // We got to the end of processing a local module. Create an - // ImportDecl as we would for an imported module. - FileID File = getSourceManager().getFileID(EomLoc); - SourceLocation DirectiveLoc; - if (EomLoc == getSourceManager().getLocForEndOfFile(File)) { - // We reached the end of a #included module header. Use the #include loc. - assert(File != getSourceManager().getMainFileID() && - "end of submodule in main source file"); - DirectiveLoc = getSourceManager().getIncludeLoc(File); - } else { - // We reached an EOM pragma. Use the pragma location. - DirectiveLoc = EomLoc; - } - BuildModuleInclude(DirectiveLoc, Mod); - - // Any further declarations are in whatever module we returned to. - if (getLangOpts().trackLocalOwningModule()) { - // The parser guarantees that this is the same context that we entered - // the module within. - for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) { - cast<Decl>(DC)->setLocalOwningModule(getCurrentModule()); - if (!getCurrentModule()) - cast<Decl>(DC)->setModuleOwnershipKind( - Decl::ModuleOwnershipKind::Unowned); - } - } -} - -void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, - Module *Mod) { - // Bail if we're not allowed to implicitly import a module here. - if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery || - VisibleModules.isVisible(Mod)) - return; - - // Create the implicit import declaration. - TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); - ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, - Loc, Mod, Loc); - TU->addDecl(ImportD); - Consumer.HandleImplicitImportDecl(ImportD); - - // Make the module visible. - getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc); - VisibleModules.setVisible(Mod, Loc); -} - -/// We have parsed the start of an export declaration, including the '{' -/// (if present). -Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, - SourceLocation LBraceLoc) { - ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc); - - // C++ Modules TS draft: - // An export-declaration shall appear in the purview of a module other than - // the global module. - if (ModuleScopes.empty() || !ModuleScopes.back().ModuleInterface) - Diag(ExportLoc, diag::err_export_not_in_module_interface); - - // An export-declaration [...] shall not contain more than one - // export keyword. - // - // The intent here is that an export-declaration cannot appear within another - // export-declaration. - if (D->isExported()) - Diag(ExportLoc, diag::err_export_within_export); - - CurContext->addDecl(D); - PushDeclContext(S, D); - D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); - return D; -} - -/// Complete the definition of an export declaration. -Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { - auto *ED = cast<ExportDecl>(D); - if (RBraceLoc.isValid()) - ED->setRBraceLoc(RBraceLoc); - - // FIXME: Diagnose export of internal-linkage declaration (including - // anonymous namespace). - - PopDeclContext(); - return D; -} - void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 0e10804a2e..f8a34573f3 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1,9 +1,8 @@ //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -246,11 +245,11 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) - << AI << Idx << AANT_ArgumentIntegerConstant + << &AI << Idx << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); else S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) - << AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); + << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -262,7 +261,7 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, if (StrictlyUnsigned && I.isSigned() && I.isNegative()) { S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer) - << AI << /*non-negative*/ 1; + << &AI << /*non-negative*/ 1; return false; } @@ -717,7 +716,8 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) + S.Diag(AL.getLoc(), + diag::err_attribute_argument_out_of_bounds_extra_info) << AL << Idx + 1 << NumParams; continue; } @@ -1119,7 +1119,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // __builtin_object_size. So, it has the same constraints as that second // argument; namely, it must be in the range [0, 3]. if (Type > 3) { - S.Diag(E->getBeginLoc(), diag::err_attribute_argument_outof_range) + S.Diag(E->getBeginLoc(), diag::err_attribute_argument_out_of_range) << AL << 0 << 3 << E->getSourceRange(); return; } @@ -2284,18 +2284,11 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y, return false; } -AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, - IdentifierInfo *Platform, - bool Implicit, - VersionTuple Introduced, - VersionTuple Deprecated, - VersionTuple Obsoleted, - bool IsUnavailable, - StringRef Message, - bool IsStrict, - StringRef Replacement, - AvailabilityMergeKind AMK, - unsigned AttrSpellingListIndex) { +AvailabilityAttr *Sema::mergeAvailabilityAttr( + NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit, + VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, + bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, + AvailabilityMergeKind AMK, int Priority, unsigned AttrSpellingListIndex) { VersionTuple MergedIntroduced = Introduced; VersionTuple MergedDeprecated = Deprecated; VersionTuple MergedObsoleted = Obsoleted; @@ -2329,16 +2322,15 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, } // If there is an existing availability attribute for this platform that - // is explicit and the new one is implicit use the explicit one and - // discard the new implicit attribute. - if (!OldAA->isImplicit() && Implicit) { + // has a lower priority use the existing one and discard the new + // attribute. + if (OldAA->getPriority() < Priority) return nullptr; - } - // If there is an existing attribute for this platform that is implicit - // and the new attribute is explicit then erase the old one and - // continue processing the attributes. - if (!Implicit && OldAA->isImplicit()) { + // If there is an existing attribute for this platform that has a higher + // priority than the new attribute then erase the old one and continue + // processing the attributes. + if (OldAA->getPriority() > Priority) { Attrs.erase(Attrs.begin() + i); --e; continue; @@ -2437,11 +2429,10 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted) && !OverrideOrImpl) { - auto *Avail = ::new (Context) AvailabilityAttr(Range, Context, Platform, - Introduced, Deprecated, - Obsoleted, IsUnavailable, Message, - IsStrict, Replacement, - AttrSpellingListIndex); + auto *Avail = ::new (Context) + AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, + Obsoleted, IsUnavailable, Message, IsStrict, + Replacement, Priority, AttrSpellingListIndex); Avail->setImplicit(Implicit); return Avail; } @@ -2484,15 +2475,13 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II, - false/*Implicit*/, - Introduced.Version, - Deprecated.Version, - Obsoleted.Version, - IsUnavailable, Str, - IsStrict, Replacement, - Sema::AMK_None, - Index); + int PriorityModifier = AL.isPragmaClangAttribute() + ? Sema::AP_PragmaClangAttribute + : Sema::AP_Explicit; + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL.getRange(), II, false /*Implicit*/, Introduced.Version, + Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, + Replacement, Sema::AMK_None, PriorityModifier, Index); if (NewAttr) D->addAttr(NewAttr); @@ -2519,6 +2508,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { else return VersionTuple(NewMajor, Version.getMinor().getValue()); } + return VersionTuple(NewMajor); } return VersionTuple(2, 0); @@ -2528,18 +2518,11 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - AL.getRange(), - NewII, - true/*Implicit*/, - NewIntroduced, - NewDeprecated, - NewObsoleted, - IsUnavailable, Str, - IsStrict, - Replacement, - Sema::AMK_None, - Index); + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL.getRange(), NewII, true /*Implicit*/, NewIntroduced, + NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict, + Replacement, Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index); if (NewAttr) D->addAttr(NewAttr); } @@ -2553,20 +2536,13 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { NewII = &S.Context.Idents.get("tvos_app_extension"); if (NewII) { - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - AL.getRange(), - NewII, - true/*Implicit*/, - Introduced.Version, - Deprecated.Version, - Obsoleted.Version, - IsUnavailable, Str, - IsStrict, - Replacement, - Sema::AMK_None, - Index); - if (NewAttr) - D->addAttr(NewAttr); + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL.getRange(), NewII, true /*Implicit*/, Introduced.Version, + Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict, + Replacement, Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index); + if (NewAttr) + D->addAttr(NewAttr); } } } @@ -3325,7 +3301,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (prioritynum < 101 || prioritynum > 65535) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range) + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) << E->getSourceRange() << AL << 101 << 65535; AL.setInvalid(); return; @@ -3480,6 +3456,146 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } +/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes. +static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The index that identifies the callback callee is mandatory. + if (AL.getNumArgs() == 0) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee) + << AL.getRange(); + return; + } + + bool HasImplicitThisParam = isInstanceMethod(D); + int32_t NumArgs = getFunctionOrMethodNumParams(D); + + FunctionDecl *FD = D->getAsFunction(); + assert(FD && "Expected a function declaration!"); + + llvm::StringMap<int> NameIdxMapping; + NameIdxMapping["__"] = -1; + + NameIdxMapping["this"] = 0; + + int Idx = 1; + for (const ParmVarDecl *PVD : FD->parameters()) + NameIdxMapping[PVD->getName()] = Idx++; + + auto UnknownName = NameIdxMapping.end(); + + SmallVector<int, 8> EncodingIndices; + for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) { + SourceRange SR; + int32_t ArgIdx; + + if (AL.isArgIdent(I)) { + IdentifierLoc *IdLoc = AL.getArgAsIdent(I); + auto It = NameIdxMapping.find(IdLoc->Ident->getName()); + if (It == UnknownName) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown) + << IdLoc->Ident << IdLoc->Loc; + return; + } + + SR = SourceRange(IdLoc->Loc); + ArgIdx = It->second; + } else if (AL.isArgExpr(I)) { + Expr *IdxExpr = AL.getArgAsExpr(I); + + // If the expression is not parseable as an int32_t we have a problem. + if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1, + false)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (I + 1) << IdxExpr->getSourceRange(); + return; + } + + // Check oob, excluding the special values, 0 and -1. + if (ArgIdx < -1 || ArgIdx > NumArgs) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << (I + 1) << IdxExpr->getSourceRange(); + return; + } + + SR = IdxExpr->getSourceRange(); + } else { + llvm_unreachable("Unexpected ParsedAttr argument type!"); + } + + if (ArgIdx == 0 && !HasImplicitThisParam) { + S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available) + << (I + 1) << SR; + return; + } + + // Adjust for the case we do not have an implicit "this" parameter. In this + // case we decrease all positive values by 1 to get LLVM argument indices. + if (!HasImplicitThisParam && ArgIdx > 0) + ArgIdx -= 1; + + EncodingIndices.push_back(ArgIdx); + } + + int CalleeIdx = EncodingIndices.front(); + // Check if the callee index is proper, thus not "this" and not "unknown". + // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam" + // is false and positive if "HasImplicitThisParam" is true. + if (CalleeIdx < (int)HasImplicitThisParam) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee) + << AL.getRange(); + return; + } + + // Get the callee type, note the index adjustment as the AST doesn't contain + // the this type (which the callee cannot reference anyway!). + const Type *CalleeType = + getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam) + .getTypePtr(); + if (!CalleeType || !CalleeType->isFunctionPointerType()) { + S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type) + << AL.getRange(); + return; + } + + const Type *CalleeFnType = + CalleeType->getPointeeType()->getUnqualifiedDesugaredType(); + + // TODO: Check the type of the callee arguments. + + const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType); + if (!CalleeFnProtoType) { + S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type) + << AL.getRange(); + return; + } + + if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL << (unsigned)(EncodingIndices.size() - 1); + return; + } + + if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL << (unsigned)(EncodingIndices.size() - 1); + return; + } + + if (CalleeFnProtoType->isVariadic()) { + S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange(); + return; + } + + // Do not allow multiple callback attributes. + if (D->hasAttr<CallbackAttr>()) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange(); + return; + } + + D->addAttr(::new (S.Context) CallbackAttr( + AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(), + AL.getAttributeSpellingListIndex())); +} + static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Try to find the underlying union declaration. RecordDecl *RD = nullptr; @@ -4157,6 +4273,15 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex); } +NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr( + Decl *D, const NoSpeculativeLoadHardeningAttr &AL) { + if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL)) + return nullptr; + + return ::new (Context) NoSpeculativeLoadHardeningAttr( + AL.getRange(), Context, AL.getSpellingListIndex()); +} + OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) { @@ -4177,6 +4302,15 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } +SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr( + Decl *D, const SpeculativeLoadHardeningAttr &AL) { + if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL)) + return nullptr; + + return ::new (Context) SpeculativeLoadHardeningAttr( + AL.getRange(), Context, AL.getSpellingListIndex()); +} + static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL)) return; @@ -4482,11 +4616,44 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, default: llvm_unreachable("unexpected attribute kind"); } + TargetInfo::CallingConvCheckResult A = TargetInfo::CCCR_OK; const TargetInfo &TI = Context.getTargetInfo(); - TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); + // CUDA functions may have host and/or device attributes which indicate + // their targeted execution environment, therefore the calling convention + // of functions in CUDA should be checked against the target deduced based + // on their host/device attributes. + if (LangOpts.CUDA) { + auto *Aux = Context.getAuxTargetInfo(); + auto CudaTarget = IdentifyCUDATarget(FD); + bool CheckHost = false, CheckDevice = false; + switch (CudaTarget) { + case CFT_HostDevice: + CheckHost = true; + CheckDevice = true; + break; + case CFT_Host: + CheckHost = true; + break; + case CFT_Device: + case CFT_Global: + CheckDevice = true; + break; + case CFT_InvalidTarget: + llvm_unreachable("unexpected cuda target"); + } + auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI; + auto *DeviceTI = LangOpts.CUDAIsDevice ? &TI : Aux; + if (CheckHost && HostTI) + A = HostTI->checkCallingConvention(CC); + if (A == TargetInfo::CCCR_OK && CheckDevice && DeviceTI) + A = DeviceTI->checkCallingConvention(CC); + } else { + A = TI.checkCallingConvention(CC); + } if (A != TargetInfo::CCCR_OK) { if (A == TargetInfo::CCCR_Warning) - Diag(Attrs.getLoc(), diag::warn_cconv_ignored) << Attrs; + Diag(Attrs.getLoc(), diag::warn_cconv_ignored) + << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget; // This convention is not valid for the target. Use the default function or // method calling convention. @@ -5116,11 +5283,22 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, static void handleObjCDesignatedInitializer(Sema &S, Decl *D, const ParsedAttr &AL) { + DeclContext *Ctx = D->getDeclContext(); + + // This attribute can only be applied to methods in interfaces or class + // extensions. + if (!isa<ObjCInterfaceDecl>(Ctx) && + !(isa<ObjCCategoryDecl>(Ctx) && + cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) { + S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init); + return; + } + ObjCInterfaceDecl *IFace; - if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx)) IFace = CatDecl->getClassInterface(); else - IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); + IFace = cast<ObjCInterfaceDecl>(Ctx); if (!IFace) return; @@ -5377,6 +5555,27 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // MSP430 'interrupt' attribute is applied to + // a function with no parameters and void return type. + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'interrupt'" << ExpectedFunctionOrMethod; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MSP430*/ 1 << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MSP430*/ 1 << 1; + return; + } + + // The attribute takes one integer argument. if (!checkAttributeNumArgs(S, AL, 1)) return; @@ -5386,8 +5585,6 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - // FIXME: Check for decl - it should be void ()(void). - Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { @@ -5396,9 +5593,9 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { << NumParamsExpr->getSourceRange(); return; } - + // The argument should be in range 0..63. unsigned Num = NumParams.getLimitedValue(255); - if ((Num & 1) || Num > 30) { + if (Num > 63) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) << AL << (int)NumParams.getSExtValue() << NumParamsExpr->getSourceRange(); @@ -5442,14 +5639,14 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute) - << 0; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MIPS*/ 0 << 0; return; } if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute) - << 1; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*MIPS*/ 0 << 1; return; } @@ -5558,6 +5755,51 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute<AVRSignalAttr>(S, D, AL); } +static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'import_module'" << ExpectedFunction; + return; + } + + auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr( + AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); +} + +static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'import_name'" << ExpectedFunction; + return; + } + + auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr( + AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); +} static void handleRISCVInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5596,12 +5838,14 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, } if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { - S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 0; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*RISC-V*/ 2 << 0; return; } if (!getFunctionOrMethodResultType(D)->isVoidType()) { - S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 1; + S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) + << /*RISC-V*/ 2 << 1; return; } @@ -5643,57 +5887,115 @@ static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } -static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { +static bool +checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr, + const AMDGPUFlatWorkGroupSizeAttr &Attr) { + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (MinExpr->isValueDependent() || MaxExpr->isValueDependent()) + return false; + uint32_t Min = 0; - Expr *MinExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, MinExpr, Min)) - return; + if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0)) + return true; uint32_t Max = 0; - Expr *MaxExpr = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, MaxExpr, Max)) - return; + if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1)) + return true; if (Min == 0 && Max != 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 0; + return true; } if (Min > Max) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 1; + return true; } - D->addAttr(::new (S.Context) - AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max, - AL.getAttributeSpellingListIndex())); + return false; } -static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t Min = 0; - Expr *MinExpr = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, MinExpr, Min)) +void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D, + Expr *MinExpr, Expr *MaxExpr, + unsigned SpellingListIndex) { + AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr, + SpellingListIndex); + + if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr)) return; + D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr( + AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex)); +} + +static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + Expr *MinExpr = AL.getArgAsExpr(0); + Expr *MaxExpr = AL.getArgAsExpr(1); + + S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr, + AL.getAttributeSpellingListIndex()); +} + +static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr, + Expr *MaxExpr, + const AMDGPUWavesPerEUAttr &Attr) { + if (S.DiagnoseUnexpandedParameterPack(MinExpr) || + (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr))) + return true; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent())) + return false; + + uint32_t Min = 0; + if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0)) + return true; + uint32_t Max = 0; - if (AL.getNumArgs() == 2) { - Expr *MaxExpr = AL.getArgAsExpr(1); - if (!checkUInt32Argument(S, AL, MaxExpr, Max)) - return; - } + if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1)) + return true; if (Min == 0 && Max != 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 0; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 0; + return true; } if (Max != 0 && Min > Max) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1; - return; + S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid) + << &Attr << 1; + return true; } - D->addAttr(::new (S.Context) - AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max, - AL.getAttributeSpellingListIndex())); + return false; +} + +void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D, + Expr *MinExpr, Expr *MaxExpr, + unsigned SpellingListIndex) { + AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr, + SpellingListIndex); + + if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr)) + return; + + D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr, + MaxExpr, SpellingListIndex)); +} + +static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) + return; + + Expr *MinExpr = AL.getArgAsExpr(0); + Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr; + + S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr, + AL.getAttributeSpellingListIndex()); } static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6001,7 +6303,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc)) return; - if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) + if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == + SanitizerMask()) S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) @@ -6114,7 +6417,9 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); if (AL.getName()->getName().find("read_write") != StringRef::npos) { - if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { + if ((!S.getLangOpts().OpenCLCPlusPlus && + S.getLangOpts().OpenCLVersion < 200) || + DeclTy->isPipeType()) { S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) << AL << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); @@ -6221,6 +6526,42 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL); } +static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Check that the return type is a `typedef int kern_return_t` or a typedef + // around it, because otherwise MIG convention checks make no sense. + // BlockDecl doesn't store a return type, so it's annoying to check, + // so let's skip it for now. + if (!isa<BlockDecl>(D)) { + QualType T = getFunctionOrMethodResultType(D); + bool IsKernReturnT = false; + while (const auto *TT = T->getAs<TypedefType>()) { + IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t"); + T = TT->desugar(); + } + if (!IsKernReturnT || T.getCanonicalType() != S.getASTContext().IntTy) { + S.Diag(D->getBeginLoc(), + diag::warn_mig_server_routine_does_not_return_kern_return_t); + return; + } + } + + handleSimpleAttribute<MIGServerRoutineAttr>(S, D, AL); +} + +static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Warn if the return type is not a pointer or reference type. + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + QualType RetTy = FD->getReturnType(); + if (!RetTy->isPointerType() && !RetTy->isReferenceType()) { + S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer) + << AL.getRange() << RetTy; + return; + } + } + + handleSimpleAttribute<MSAllocatorAttr>(S, D, AL); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -6311,6 +6652,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AVRSignal: handleAVRSignalAttr(S, D, AL); break; + case ParsedAttr::AT_WebAssemblyImportModule: + handleWebAssemblyImportModuleAttr(S, D, AL); + break; + case ParsedAttr::AT_WebAssemblyImportName: + handleWebAssemblyImportNameAttr(S, D, AL); + break; case ParsedAttr::AT_IBAction: handleSimpleAttribute<IBActionAttr>(S, D, AL); break; @@ -6414,6 +6761,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_FormatArg: handleFormatArgAttr(S, D, AL); break; + case ParsedAttr::AT_Callback: + handleCallbackAttr(S, D, AL); + break; case ParsedAttr::AT_CUDAGlobal: handleGlobalAttr(S, D, AL); break; @@ -6599,7 +6949,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSectionAttr(S, D, AL); break; case ParsedAttr::AT_SpeculativeLoadHardening: - handleSimpleAttribute<SpeculativeLoadHardeningAttr>(S, D, AL); + handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr, + NoSpeculativeLoadHardeningAttr>(S, D, + AL); + break; + case ParsedAttr::AT_NoSpeculativeLoadHardening: + handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr, + SpeculativeLoadHardeningAttr>(S, D, AL); break; case ParsedAttr::AT_CodeSeg: handleCodeSegAttr(S, D, AL); @@ -6619,6 +6975,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCRootClass: handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); break; + case ParsedAttr::AT_ObjCNonLazyClass: + handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL); + break; case ParsedAttr::AT_ObjCSubclassingRestricted: handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL); break; @@ -6932,6 +7291,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCExternallyRetained: handleObjCExternallyRetainedAttr(S, D, AL); break; + + case ParsedAttr::AT_MIGServerRoutine: + handleMIGServerRoutineAttr(S, D, AL); + break; + + case ParsedAttr::AT_MSAllocator: + handleMSAllocatorAttr(S, D, AL); + break; } } @@ -6997,6 +7364,17 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } } + + // Do this check after processing D's attributes because the attribute + // objc_method_family can change whether the given method is in the init + // family, and it can be applied after objc_designated_initializer. This is a + // bit of a hack, but we need it to be compatible with versions of clang that + // processed the attribute list in the wrong order. + if (D->hasAttr<ObjCDesignatedInitializerAttr>() && + cast<ObjCMethodDecl>(D)->getMethodFamily() != OMF_init) { + Diag(D->getLocation(), diag::err_designated_init_attr_non_init); + D->dropAttr<ObjCDesignatedInitializerAttr>(); + } } // Helper for delayed processing TransparentUnion attribute. @@ -7346,13 +7724,11 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return true; } else if (K == AR_Unavailable) { // It is perfectly fine to refer to an 'unavailable' Objective-C method - // when it's actually defined and is referenced from within the - // @implementation itself. In this context, we interpret unavailable as a - // form of access control. + // when it is referenced from within the @implementation itself. In this + // context, we interpret unavailable as a form of access control. if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { - if (MD->getClassInterface() == Impl->getClassInterface() && - MD->isDefined()) + if (MD->getClassInterface() == Impl->getClassInterface()) return true; } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 43b289d8d0..7e4aab0fae 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1,9 +1,8 @@ //===------ SemaDeclCXX.cpp - Semantic Analysis for C++ Declarations ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -1129,7 +1128,6 @@ static bool checkTupleLikeDecomposition(Sema &S, } } } - S.FilterAcceptableTemplateNames(MemberGet); } unsigned I = 0; @@ -1301,6 +1299,10 @@ static DeclAccessPair findDecomposableBaseClass(Sema &S, SourceLocation Loc, static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, ValueDecl *Src, QualType DecompType, const CXXRecordDecl *OrigRD) { + if (S.RequireCompleteType(Src->getLocation(), DecompType, + diag::err_incomplete_type)) + return true; + CXXCastPath BasePath; DeclAccessPair BasePair = findDecomposableBaseClass(S, Src->getLocation(), OrigRD, BasePath); @@ -3172,7 +3174,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // declared] with the same access [as the template]. if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(NonTemplateMember)) { auto *TD = DG->getDeducedTemplate(); - if (AS != TD->getAccess()) { + // Access specifiers are only meaningful if both the template and the + // deduction guide are from the same scope. + if (AS != TD->getAccess() && + TD->getDeclContext()->getRedeclContext()->Equals( + DG->getDeclContext()->getRedeclContext())) { Diag(DG->getBeginLoc(), diag::err_deduction_guide_wrong_access); Diag(TD->getBeginLoc(), diag::note_deduction_guide_template_access) << TD->getAccess(); @@ -3775,7 +3781,7 @@ namespace { // Callback to only accept typo corrections that can be a valid C++ member // intializer: either a non-static field member or a base class. -class MemInitializerValidatorCCC : public CorrectionCandidateCallback { +class MemInitializerValidatorCCC final : public CorrectionCandidateCallback { public: explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl) : ClassDecl(ClassDecl) {} @@ -3789,6 +3795,10 @@ public: return false; } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<MemInitializerValidatorCCC>(*this); + } + private: CXXRecordDecl *ClassDecl; }; @@ -3918,11 +3928,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD, // If no results were found, try to correct typos. TypoCorrection Corr; + MemInitializerValidatorCCC CCC(ClassDecl); if (R.empty() && BaseType.isNull() && - (Corr = CorrectTypo( - R.getLookupNameInfo(), R.getLookupKind(), S, &SS, - llvm::make_unique<MemInitializerValidatorCCC>(ClassDecl), - CTK_ErrorRecovery, ClassDecl))) { + (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, + CCC, CTK_ErrorRecovery, ClassDecl))) { if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) { // We have found a non-static data member with a similar // name to what was typed; complain and initialize that @@ -5688,9 +5697,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); - // Ignore explicit dllexport on explicit class template instantiation declarations. + // Ignore explicit dllexport on explicit class template instantiation + // declarations, except in MinGW mode. if (ClassExported && !ClassAttr->isInherited() && - TSK == TSK_ExplicitInstantiationDeclaration) { + TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { Class->dropAttr<DLLExportAttr>(); return; } @@ -5715,9 +5726,12 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { continue; if (MD->isInlined()) { - // MinGW does not import or export inline methods. + // MinGW does not import or export inline methods. But do it for + // template instantiations. if (!Context.getTargetInfo().getCXXABI().isMicrosoft() && - !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) + !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() && + TSK != TSK_ExplicitInstantiationDeclaration && + TSK != TSK_ExplicitInstantiationDefinition) continue; // MSVC versions before 2015 don't export the move assignment operators @@ -5886,9 +5900,6 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, if (D->isDependentType() || D->isInvalidDecl()) return false; - if (D->hasAttr<TrivialABIAttr>()) - return true; - // Clang <= 4 used the pre-C++11 rule, which ignores move operations. // The PS4 platform ABI follows the behavior of Clang 3.2. if (CCK == TargetInfo::CCK_ClangABI4OrPS4) @@ -5946,8 +5957,11 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, // Note: This permits small classes with nontrivial destructors to be // passed in registers, which is non-conforming. + bool isAArch64 = S.Context.getTargetInfo().getTriple().isAArch64(); + uint64_t TypeSize = isAArch64 ? 128 : 64; + if (CopyCtorIsTrivial && - S.getASTContext().getTypeSize(D->getTypeForDecl()) <= 64) + S.getASTContext().getTypeSize(D->getTypeForDecl()) <= TypeSize) return true; return false; } @@ -6553,7 +6567,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { ReturnType = Type->getReturnType(); QualType DeclType = Context.getTypeDeclType(RD); - DeclType = Context.getAddrSpaceQualType(DeclType, MD->getTypeQualifiers().getAddressSpace()); + DeclType = Context.getAddrSpaceQualType(DeclType, MD->getMethodQualifiers().getAddressSpace()); QualType ExpectedReturnType = Context.getLValueReferenceType(DeclType); if (!Context.hasSameType(ReturnType, ExpectedReturnType)) { @@ -6563,7 +6577,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { } // A defaulted special member cannot have cv-qualifiers. - if (Type->getTypeQuals().hasConst() || Type->getTypeQuals().hasVolatile()) { + if (Type->getMethodQuals().hasConst() || Type->getMethodQuals().hasVolatile()) { if (DeleteOnTypeMismatch) ShouldDeleteForTypeMismatch = true; else { @@ -6623,6 +6637,8 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // makes such functions always instantiate to constexpr functions. For // functions which cannot be constexpr (for non-constructors in C++11 and for // destructors in C++1y), this is checked elsewhere. + // + // FIXME: This should not apply if the member is deleted. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) @@ -6634,38 +6650,26 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { HadError = true; } - // and may have an explicit exception-specification only if it is compatible - // with the exception-specification on the implicit declaration. - if (Type->hasExceptionSpec()) { - // Delay the check if this is the first declaration of the special member, - // since we may not have parsed some necessary in-class initializers yet. - if (First) { - // If the exception specification needs to be instantiated, do so now, - // before we clobber it with an EST_Unevaluated specification below. - if (Type->getExceptionSpecType() == EST_Uninstantiated) { - InstantiateExceptionSpec(MD->getBeginLoc(), MD); - Type = MD->getType()->getAs<FunctionProtoType>(); - } - DelayedDefaultedMemberExceptionSpecs.push_back(std::make_pair(MD, Type)); - } else - CheckExplicitlyDefaultedMemberExceptionSpec(MD, Type); - } - - // If a function is explicitly defaulted on its first declaration, if (First) { - // -- it is implicitly considered to be constexpr if the implicit - // definition would be, + // C++2a [dcl.fct.def.default]p3: + // If a function is explicitly defaulted on its first declaration, it is + // implicitly considered to be constexpr if the implicit declaration + // would be. MD->setConstexpr(Constexpr); - // -- it is implicitly considered to have the same exception-specification - // as if it had been implicitly declared, - FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); - EPI.ExceptionSpec.Type = EST_Unevaluated; - EPI.ExceptionSpec.SourceDecl = MD; - MD->setType(Context.getFunctionType(ReturnType, - llvm::makeArrayRef(&ArgType, - ExpectedParams), - EPI)); + if (!Type->hasExceptionSpec()) { + // C++2a [except.spec]p3: + // If a declaration of a function does not have a noexcept-specifier + // [and] is defaulted on its first declaration, [...] the exception + // specification is as specified below + FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = MD; + MD->setType(Context.getFunctionType(ReturnType, + llvm::makeArrayRef(&ArgType, + ExpectedParams), + EPI)); + } } if (ShouldDeleteForTypeMismatch || ShouldDeleteSpecialMember(MD, CSM)) { @@ -6698,43 +6702,12 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { MD->setInvalidDecl(); } -/// Check whether the exception specification provided for an -/// explicitly-defaulted special member matches the exception specification -/// that would have been generated for an implicit special member, per -/// C++11 [dcl.fct.def.default]p2. -void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( - CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) { - // If the exception specification was explicitly specified but hadn't been - // parsed when the method was defaulted, grab it now. - if (SpecifiedType->getExceptionSpecType() == EST_Unparsed) - SpecifiedType = - MD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); - - // Compute the implicit exception specification. - CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false, - /*IsCXXMethod=*/true); - FunctionProtoType::ExtProtoInfo EPI(CC); - auto IES = computeImplicitExceptionSpec(*this, MD->getLocation(), MD); - EPI.ExceptionSpec = IES.getExceptionSpec(); - const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( - Context.getFunctionType(Context.VoidTy, None, EPI)); - - // Ensure that it matches. - CheckEquivalentExceptionSpec( - PDiag(diag::err_incorrect_defaulted_exception_spec) - << getSpecialMember(MD), PDiag(), - ImplicitType, SourceLocation(), - SpecifiedType, MD->getLocation()); -} - void Sema::CheckDelayedMemberExceptionSpecs() { decltype(DelayedOverridingExceptionSpecChecks) Overriding; decltype(DelayedEquivalentExceptionSpecChecks) Equivalent; - decltype(DelayedDefaultedMemberExceptionSpecs) Defaulted; std::swap(Overriding, DelayedOverridingExceptionSpecChecks); std::swap(Equivalent, DelayedEquivalentExceptionSpecChecks); - std::swap(Defaulted, DelayedDefaultedMemberExceptionSpecs); // Perform any deferred checking of exception specifications for virtual // destructors. @@ -6745,11 +6718,6 @@ void Sema::CheckDelayedMemberExceptionSpecs() { // special members. for (auto &Check : Equivalent) CheckEquivalentExceptionSpec(Check.second, Check.first); - - // Check that any explicitly-defaulted methods have exception specifications - // compatible with their implicit exception specifications. - for (auto &Spec : Defaulted) - CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second); } namespace { @@ -6891,6 +6859,8 @@ struct SpecialMemberDeletionInfo return ICI ? Sema::CXXInvalid : CSM; } + bool shouldDeleteForVariantObjCPtrMember(FieldDecl *FD, QualType FieldType); + bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); } bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); } @@ -6962,13 +6932,14 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( S.Diag(Field->getLocation(), diag::note_deleted_special_member_class_subobject) << getEffectiveCSM() << MD->getParent() << /*IsField*/true - << Field << DiagKind << IsDtorCallInCtor; + << Field << DiagKind << IsDtorCallInCtor << /*IsObjCPtr*/false; } else { CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>(); S.Diag(Base->getBeginLoc(), diag::note_deleted_special_member_class_subobject) << getEffectiveCSM() << MD->getParent() << /*IsField*/ false - << Base->getType() << DiagKind << IsDtorCallInCtor; + << Base->getType() << DiagKind << IsDtorCallInCtor + << /*IsObjCPtr*/false; } if (DiagKind == 1) @@ -7020,6 +6991,30 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( return false; } +bool SpecialMemberDeletionInfo::shouldDeleteForVariantObjCPtrMember( + FieldDecl *FD, QualType FieldType) { + // The defaulted special functions are defined as deleted if this is a variant + // member with a non-trivial ownership type, e.g., ObjC __strong or __weak + // type under ARC. + if (!FieldType.hasNonTrivialObjCLifetime()) + return false; + + // Don't make the defaulted default constructor defined as deleted if the + // member has an in-class initializer. + if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer()) + return false; + + if (Diagnose) { + auto *ParentClass = cast<CXXRecordDecl>(FD->getParent()); + S.Diag(FD->getLocation(), + diag::note_deleted_special_member_class_subobject) + << getEffectiveCSM() << ParentClass << /*IsField*/true + << FD << 4 << /*IsDtorCallInCtor*/false << /*IsObjCPtr*/true; + } + + return true; +} + /// Check whether we should delete a special member function due to the class /// having a particular direct or virtual base class. bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { @@ -7040,7 +7035,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { S.Diag(Base->getBeginLoc(), diag::note_deleted_special_member_class_subobject) << getEffectiveCSM() << MD->getParent() << /*IsField*/ false - << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false; + << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false + << /*IsObjCPtr*/false; S.NoteDeletedFunction(BaseCtor); } return BaseCtor->isDeleted(); @@ -7054,6 +7050,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { QualType FieldType = S.Context.getBaseElementType(FD->getType()); CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); + if (inUnion() && shouldDeleteForVariantObjCPtrMember(FD, FieldType)) + return true; + if (CSM == Sema::CXXDefaultConstructor) { // For a default constructor, all references must be initialized in-class // and, if a union, it must have a non-const member. @@ -7115,6 +7114,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { for (auto *UI : FieldRecord->fields()) { QualType UnionFieldType = S.Context.getBaseElementType(UI->getType()); + if (shouldDeleteForVariantObjCPtrMember(&*UI, UnionFieldType)) + return true; + if (!UnionFieldType.isConstQualified()) AllVariantFieldsAreConst = false; @@ -7934,14 +7936,14 @@ void Sema::ActOnFinishCXXMemberSpecification( /// definition of the class is complete. void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { if (ClassDecl->needsImplicitDefaultConstructor()) { - ++ASTContext::NumImplicitDefaultConstructors; + ++getASTContext().NumImplicitDefaultConstructors; if (ClassDecl->hasInheritedConstructor()) DeclareImplicitDefaultConstructor(ClassDecl); } if (ClassDecl->needsImplicitCopyConstructor()) { - ++ASTContext::NumImplicitCopyConstructors; + ++getASTContext().NumImplicitCopyConstructors; // If the properties or semantics of the copy constructor couldn't be // determined while the class was being declared, force a declaration @@ -7963,7 +7965,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) { - ++ASTContext::NumImplicitMoveConstructors; + ++getASTContext().NumImplicitMoveConstructors; if (ClassDecl->needsOverloadResolutionForMoveConstructor() || ClassDecl->hasInheritedConstructor()) @@ -7971,7 +7973,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } if (ClassDecl->needsImplicitCopyAssignment()) { - ++ASTContext::NumImplicitCopyAssignmentOperators; + ++getASTContext().NumImplicitCopyAssignmentOperators; // If we have a dynamic class, then the copy assignment operator may be // virtual, so we have to declare it immediately. This ensures that, e.g., @@ -7984,7 +7986,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) { - ++ASTContext::NumImplicitMoveAssignmentOperators; + ++getASTContext().NumImplicitMoveAssignmentOperators; // Likewise for the move assignment operator. if (ClassDecl->isDynamicClass() || @@ -7994,7 +7996,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } if (ClassDecl->needsImplicitDestructor()) { - ++ASTContext::NumImplicitDestructors; + ++getASTContext().NumImplicitDestructors; // If we have a dynamic class, then the destructor may be virtual, so we // have to declare the destructor immediately. This ensures that, e.g., it @@ -8997,6 +8999,9 @@ void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) { PopDeclContext(); if (Namespc->hasAttr<VisibilityAttr>()) PopPragmaVisibility(true, RBrace); + // If this namespace contains an export-declaration, export it now. + if (DeferredExportedNamespaces.erase(Namespc)) + Dcl->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); } CXXRecordDecl *Sema::getStdBadAlloc() const { @@ -9316,13 +9321,17 @@ static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) { namespace { // Callback to only accept typo corrections that are namespaces. -class NamespaceValidatorCCC : public CorrectionCandidateCallback { +class NamespaceValidatorCCC final : public CorrectionCandidateCallback { public: bool ValidateCandidate(const TypoCorrection &candidate) override { if (NamedDecl *ND = candidate.getCorrectionDecl()) return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); return false; } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<NamespaceValidatorCCC>(*this); + } }; } @@ -9332,9 +9341,9 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, SourceLocation IdentLoc, IdentifierInfo *Ident) { R.clear(); + NamespaceValidatorCCC CCC{}; if (TypoCorrection Corrected = - S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS, - llvm::make_unique<NamespaceValidatorCCC>(), + S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS, CCC, Sema::CTK_ErrorRecovery)) { if (DeclContext *DC = S.computeDeclContext(SS, false)) { std::string CorrectedStr(Corrected.getAsString(S.getLangOpts())); @@ -9829,7 +9838,7 @@ static CXXBaseSpecifier *findDirectBaseWithType(CXXRecordDecl *Derived, } namespace { -class UsingValidatorCCC : public CorrectionCandidateCallback { +class UsingValidatorCCC final : public CorrectionCandidateCallback { public: UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation, NestedNameSpecifier *NNS, CXXRecordDecl *RequireMemberOf) @@ -9899,6 +9908,10 @@ public: return !HasTypenameKeyword; } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<UsingValidatorCCC>(*this); + } + private: bool HasTypenameKeyword; bool IsInstantiation; @@ -10055,12 +10068,11 @@ NamedDecl *Sema::BuildUsingDeclaration( isa<TranslationUnitDecl>(LookupContext) && getSourceManager().isInSystemHeader(UsingLoc)) return nullptr; - if (TypoCorrection Corrected = CorrectTypo( - R.getLookupNameInfo(), R.getLookupKind(), S, &SS, - llvm::make_unique<UsingValidatorCCC>( - HasTypenameKeyword, IsInstantiation, SS.getScopeRep(), - dyn_cast<CXXRecordDecl>(CurContext)), - CTK_ErrorRecovery)) { + UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, SS.getScopeRep(), + dyn_cast<CXXRecordDecl>(CurContext)); + if (TypoCorrection Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, + CTK_ErrorRecovery)) { // We reject candidates where DroppedSpecifier == true, hence the // literal '0' below. diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest) @@ -10976,7 +10988,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); // Note that we have declared this constructor. - ++ASTContext::NumImplicitDefaultConstructorsDeclared; + ++getASTContext().NumImplicitDefaultConstructorsDeclared; Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, DefaultCon); @@ -11249,7 +11261,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { ClassDecl->hasTrivialDestructorForCall()); // Note that we have declared this destructor. - ++ASTContext::NumImplicitDestructorsDeclared; + ++getASTContext().NumImplicitDestructorsDeclared; Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, Destructor); @@ -11319,7 +11331,6 @@ void Sema::ActOnFinishCXXMemberDecls() { if (Record->isInvalidDecl()) { DelayedOverridingExceptionSpecChecks.clear(); DelayedEquivalentExceptionSpecChecks.clear(); - DelayedDefaultedMemberExceptionSpecs.clear(); return; } checkForMultipleExportedDefaultConstructors(*this, Record); @@ -11810,14 +11821,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { return nullptr; QualType ArgType = Context.getTypeDeclType(ClassDecl); + if (Context.getLangOpts().OpenCLCPlusPlus) + ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); QualType RetType = Context.getLValueReferenceType(ArgType); bool Const = ClassDecl->implicitCopyAssignmentHasConstParam(); if (Const) ArgType = ArgType.withConst(); - if (Context.getLangOpts().OpenCLCPlusPlus) - ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); - ArgType = Context.getLValueReferenceType(ArgType); bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, @@ -11860,7 +11870,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { : ClassDecl->hasTrivialCopyAssignment()); // Note that we have added this copy-assignment operator. - ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; + ++getASTContext().NumImplicitCopyAssignmentOperatorsDeclared; Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyAssignment); @@ -12009,7 +12019,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, DerefBuilder DerefThis(This); CastBuilder To(DerefThis, Context.getQualifiedType( - BaseType, CopyAssignOperator->getTypeQualifiers()), + BaseType, CopyAssignOperator->getMethodQualifiers()), VK_LValue, BasePath); // Build the copy. @@ -12135,6 +12145,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // constructor rules. QualType ArgType = Context.getTypeDeclType(ClassDecl); + if (Context.getLangOpts().OpenCLCPlusPlus) + ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); QualType RetType = Context.getLValueReferenceType(ArgType); ArgType = Context.getRValueReferenceType(ArgType); @@ -12181,7 +12193,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { : ClassDecl->hasTrivialMoveAssignment()); // Note that we have added this copy-assignment operator. - ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; + ++getASTContext().NumImplicitMoveAssignmentOperatorsDeclared; Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, MoveAssignment); @@ -12374,7 +12386,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // Implicitly cast "this" to the appropriately-qualified base type. CastBuilder To(DerefThis, Context.getQualifiedType( - BaseType, MoveAssignOperator->getTypeQualifiers()), + BaseType, MoveAssignOperator->getMethodQualifiers()), VK_LValue, BasePath); // Build the move. @@ -12564,7 +12576,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( : ClassDecl->hasTrivialCopyConstructorForCall())); // Note that we have declared this constructor. - ++ASTContext::NumImplicitCopyConstructorsDeclared; + ++getASTContext().NumImplicitCopyConstructorsDeclared; Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyConstructor); @@ -12694,7 +12706,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( : ClassDecl->hasTrivialMoveConstructorForCall())); // Note that we have declared this constructor. - ++ASTContext::NumImplicitMoveConstructorsDeclared; + ++getASTContext().NumImplicitMoveConstructorsDeclared; Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, MoveConstructor); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 3746bdad03..5ff1f9e340 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1,9 +1,8 @@ //===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -360,6 +359,7 @@ HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) { /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { + ImplicitlyRetainedSelfLocs.clear(); assert((getCurMethodDecl() == nullptr) && "Methodparsing confused"); ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D); @@ -500,7 +500,7 @@ namespace { // Callback to only accept typo corrections that are Objective-C classes. // If an ObjCInterfaceDecl* is given to the constructor, then the validation // function will reject corrections to that class. -class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback { +class ObjCInterfaceValidatorCCC final : public CorrectionCandidateCallback { public: ObjCInterfaceValidatorCCC() : CurrentIDecl(nullptr) {} explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl) @@ -511,6 +511,10 @@ class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback { return ID && !declaresSameEntity(ID, CurrentIDecl); } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<ObjCInterfaceValidatorCCC>(*this); + } + private: ObjCInterfaceDecl *CurrentIDecl; }; @@ -550,11 +554,10 @@ ActOnSuperClassOfClassInterface(Scope *S, if (!PrevDecl) { // Try to correct for a typo in the superclass name without correcting // to the class we're defining. + ObjCInterfaceValidatorCCC CCC(IDecl); if (TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(SuperName, SuperLoc), - LookupOrdinaryName, TUScope, - nullptr, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), - CTK_ErrorRecovery)) { + DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, + TUScope, nullptr, CCC, CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) << SuperName << ClassName); PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); @@ -1293,11 +1296,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, for (const IdentifierLocPair &Pair : ProtocolId) { ObjCProtocolDecl *PDecl = LookupProtocol(Pair.first, Pair.second); if (!PDecl) { + DeclFilterCCC<ObjCProtocolDecl> CCC{}; TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(Pair.first, Pair.second), - LookupObjCProtocolName, TUScope, nullptr, - llvm::make_unique<DeclFilterCCC<ObjCProtocolDecl>>(), - CTK_ErrorRecovery); + DeclarationNameInfo(Pair.first, Pair.second), LookupObjCProtocolName, + TUScope, nullptr, CCC, CTK_ErrorRecovery); if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest) << Pair.first); @@ -1335,7 +1337,8 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, namespace { // Callback to only accept typo corrections that are either // Objective-C protocols or valid Objective-C type arguments. -class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { +class ObjCTypeArgOrProtocolValidatorCCC final + : public CorrectionCandidateCallback { ASTContext &Context; Sema::LookupNameKind LookupKind; public: @@ -1382,6 +1385,10 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { return false; } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this); + } }; } // end anonymous namespace @@ -1671,12 +1678,10 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( } // Perform typo correction on the name. - TypoCorrection corrected = CorrectTypo( - DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S, - nullptr, - llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context, - lookupKind), - CTK_ErrorRecovery); + ObjCTypeArgOrProtocolValidatorCCC CCC(Context, lookupKind); + TypoCorrection corrected = + CorrectTypo(DeclarationNameInfo(identifiers[i], identifierLocs[i]), + lookupKind, S, nullptr, CCC, CTK_ErrorRecovery); if (corrected) { // Did we find a protocol? if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) { @@ -1888,7 +1893,8 @@ Decl *Sema::ActOnStartCategoryInterface( Decl *Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CatName, SourceLocation CatLoc) { + IdentifierInfo *CatName, SourceLocation CatLoc, + const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); ObjCCategoryDecl *CatIDecl = nullptr; if (IDecl && IDecl->hasDefinition()) { @@ -1916,6 +1922,9 @@ Decl *Sema::ActOnStartCategoryImplementation( CDecl->setInvalidDecl(); } + ProcessDeclAttributeList(TUScope, CDecl, Attrs); + AddPragmaAttributes(TUScope, CDecl); + // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -1951,7 +1960,8 @@ Decl *Sema::ActOnStartClassImplementation( SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc) { + SourceLocation SuperClassLoc, + const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = nullptr; // Check for another declaration kind with the same name. NamedDecl *PrevDecl @@ -1968,9 +1978,10 @@ Decl *Sema::ActOnStartClassImplementation( } else { // We did not find anything with the name ClassName; try to correct for // typos in the class name. - TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope, - nullptr, llvm::make_unique<ObjCInterfaceValidatorCCC>(), CTK_NonError); + ObjCInterfaceValidatorCCC CCC{}; + TypoCorrection Corrected = + CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc), + LookupOrdinaryName, TUScope, nullptr, CCC, CTK_NonError); if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { // Suggest the (potentially) correct interface name. Don't provide a // code-modification hint or use the typo name for recovery, because @@ -2044,6 +2055,9 @@ Decl *Sema::ActOnStartClassImplementation( ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl, ClassLoc, AtClassImplLoc, SuperClassLoc); + ProcessDeclAttributeList(TUScope, IMPDecl, Attrs); + AddPragmaAttributes(TUScope, IMPDecl); + if (CheckObjCDeclScope(IMPDecl)) return ActOnObjCContainerStartDefinition(IMPDecl); @@ -4152,13 +4166,12 @@ namespace { /// overrides. class OverrideSearch { public: - Sema &S; - ObjCMethodDecl *Method; + const ObjCMethodDecl *Method; llvm::SmallSetVector<ObjCMethodDecl*, 4> Overridden; bool Recursive; public: - OverrideSearch(Sema &S, ObjCMethodDecl *method) : S(S), Method(method) { + OverrideSearch(Sema &S, const ObjCMethodDecl *method) : Method(method) { Selector selector = method->getSelector(); // Bypass this search if we've never seen an instance/class method @@ -4172,19 +4185,20 @@ public: if (it == S.MethodPool.end()) return; } - ObjCMethodList &list = + const ObjCMethodList &list = method->isInstanceMethod() ? it->second.first : it->second.second; if (!list.getMethod()) return; - ObjCContainerDecl *container + const ObjCContainerDecl *container = cast<ObjCContainerDecl>(method->getDeclContext()); // Prevent the search from reaching this container again. This is // important with categories, which override methods from the // interface and each other. - if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(container)) { + if (const ObjCCategoryDecl *Category = + dyn_cast<ObjCCategoryDecl>(container)) { searchFromContainer(container); - if (ObjCInterfaceDecl *Interface = Category->getClassInterface()) + if (const ObjCInterfaceDecl *Interface = Category->getClassInterface()) searchFromContainer(Interface); } else { searchFromContainer(container); @@ -4196,7 +4210,7 @@ public: iterator end() const { return Overridden.end(); } private: - void searchFromContainer(ObjCContainerDecl *container) { + void searchFromContainer(const ObjCContainerDecl *container) { if (container->isInvalidDecl()) return; switch (container->getDeclKind()) { @@ -4212,7 +4226,7 @@ private: } } - void searchFrom(ObjCProtocolDecl *protocol) { + void searchFrom(const ObjCProtocolDecl *protocol) { if (!protocol->hasDefinition()) return; @@ -4221,14 +4235,14 @@ private: search(protocol->getReferencedProtocols()); } - void searchFrom(ObjCCategoryDecl *category) { + void searchFrom(const ObjCCategoryDecl *category) { // A method in a category declaration overrides declarations from // the main class and from protocols the category references. // The main class is handled in the constructor. search(category->getReferencedProtocols()); } - void searchFrom(ObjCCategoryImplDecl *impl) { + void searchFrom(const ObjCCategoryImplDecl *impl) { // A method in a category definition that has a category // declaration overrides declarations from the category // declaration. @@ -4238,12 +4252,12 @@ private: search(Interface); // Otherwise it overrides declarations from the class. - } else if (ObjCInterfaceDecl *Interface = impl->getClassInterface()) { + } else if (const auto *Interface = impl->getClassInterface()) { search(Interface); } } - void searchFrom(ObjCInterfaceDecl *iface) { + void searchFrom(const ObjCInterfaceDecl *iface) { // A method in a class declaration overrides declarations from if (!iface->hasDefinition()) return; @@ -4260,20 +4274,19 @@ private: search(iface->getReferencedProtocols()); } - void searchFrom(ObjCImplementationDecl *impl) { + void searchFrom(const ObjCImplementationDecl *impl) { // A method in a class implementation overrides declarations from // the class interface. - if (ObjCInterfaceDecl *Interface = impl->getClassInterface()) + if (const auto *Interface = impl->getClassInterface()) search(Interface); } void search(const ObjCProtocolList &protocols) { - for (ObjCProtocolList::iterator i = protocols.begin(), e = protocols.end(); - i != e; ++i) - search(*i); + for (const auto *Proto : protocols) + search(Proto); } - void search(ObjCContainerDecl *container) { + void search(const ObjCContainerDecl *container) { // Check for a method in this container which matches this selector. ObjCMethodDecl *meth = container->getMethod(Method->getSelector(), Method->isInstanceMethod(), @@ -4299,6 +4312,8 @@ private: void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCInterfaceDecl *CurrentClass, ResultTypeCompatibilityKind RTC) { + if (!ObjCMethod) + return; // Search for overridden methods and merge information down from them. OverrideSearch overrides(*this, ObjCMethod); // Keep track if the method overrides any method in the class's base classes, @@ -4307,10 +4322,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, // For this info, a method in an implementation is not considered as // overriding the same method in the interface or its categories. bool hasOverriddenMethodsInBaseOrProtocol = false; - for (OverrideSearch::iterator - i = overrides.begin(), e = overrides.end(); i != e; ++i) { - ObjCMethodDecl *overridden = *i; - + for (ObjCMethodDecl *overridden : overrides) { if (!hasOverriddenMethodsInBaseOrProtocol) { if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || CurrentClass != overridden->getClassInterface() || @@ -4337,9 +4349,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, if (CategCount > 1 || !isa<ObjCCategoryImplDecl>(overridden->getDeclContext())) { OverrideSearch overrides(*this, overridden); - for (OverrideSearch::iterator - OI= overrides.begin(), OE= overrides.end(); OI!=OE; ++OI) { - ObjCMethodDecl *SuperOverridden = *OI; + for (ObjCMethodDecl *SuperOverridden : overrides) { if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) || CurrentClass != SuperOverridden->getClassInterface()) { hasOverriddenMethodsInBaseOrProtocol = true; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index e0850feaff..eb2bfec79d 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1,9 +1,8 @@ //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d5416d4d05..a06e7dc51e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1,9 +1,8 @@ //===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -311,6 +310,19 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, return true; } + // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions + // List-items in map clauses on this construct may only refer to the declared + // variable var and entities that could be referenced by a procedure defined + // at the same location + auto *DMD = dyn_cast<OMPDeclareMapperDecl>(CurContext); + if (LangOpts.OpenMP && DMD && !CurContext->containsDecl(D) && + isa<VarDecl>(D)) { + Diag(Loc, diag::err_omp_declare_mapper_wrong_var) + << DMD->getVarName().getAsString(); + Diag(D->getLocation(), diag::note_entity_declared_at) << D; + return true; + } + DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess, AvoidPartialAvailabilityChecks, ClassReceiver); @@ -321,17 +333,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, return false; } -/// Retrieve the message suffix that should be added to a -/// diagnostic complaining about the given function being deleted or -/// unavailable. -std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) { - std::string Message; - if (FD->getAvailability(&Message)) - return ": " + Message; - - return std::string(); -} - /// DiagnoseSentinelCalls - This routine checks whether a call or /// message-send is to a declaration with the sentinel attribute, and /// if so, it checks that the requirements of the sentinel are @@ -738,33 +739,20 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { return ExprError(); E = Res.get(); - QualType ScalarTy = Ty; - unsigned NumElts = 0; - if (const ExtVectorType *VecTy = Ty->getAs<ExtVectorType>()) { - NumElts = VecTy->getNumElements(); - ScalarTy = VecTy->getElementType(); - } - // If this is a 'float' or '__fp16' (CVR qualified or typedef) // promote to double. // Note that default argument promotion applies only to float (and // half/fp16); it does not apply to _Float16. - const BuiltinType *BTy = ScalarTy->getAs<BuiltinType>(); + const BuiltinType *BTy = Ty->getAs<BuiltinType>(); if (BTy && (BTy->getKind() == BuiltinType::Half || BTy->getKind() == BuiltinType::Float)) { if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp64")) { - if (BTy->getKind() == BuiltinType::Half) { - QualType Ty = Context.FloatTy; - if (NumElts != 0) - Ty = Context.getExtVectorType(Ty, NumElts); - E = ImpCastExprToType(E, Ty, CK_FloatingCast).get(); - } + if (BTy->getKind() == BuiltinType::Half) { + E = ImpCastExprToType(E, Context.FloatTy, CK_FloatingCast).get(); + } } else { - QualType Ty = Context.DoubleTy; - if (NumElts != 0) - Ty = Context.getExtVectorType(Ty, NumElts); - E = ImpCastExprToType(E, Ty, CK_FloatingCast).get(); + E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get(); } } @@ -923,8 +911,9 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, UnqualifiedId Name; Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), E->getBeginLoc()); - ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, - Name, true, false); + ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name, + /*HasTrailingLParen=*/true, + /*IsAddressOfOperand=*/false); if (TrapFn.isInvalid()) return ExprError(); @@ -1250,6 +1239,93 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS, return ComplexType; } +/// Return the rank of a given fixed point or integer type. The value itself +/// doesn't matter, but the values must be increasing with proper increasing +/// rank as described in N1169 4.1.1. +static unsigned GetFixedPointRank(QualType Ty) { + const auto *BTy = Ty->getAs<BuiltinType>(); + assert(BTy && "Expected a builtin type."); + + switch (BTy->getKind()) { + case BuiltinType::ShortFract: + case BuiltinType::UShortFract: + case BuiltinType::SatShortFract: + case BuiltinType::SatUShortFract: + return 1; + case BuiltinType::Fract: + case BuiltinType::UFract: + case BuiltinType::SatFract: + case BuiltinType::SatUFract: + return 2; + case BuiltinType::LongFract: + case BuiltinType::ULongFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatULongFract: + return 3; + case BuiltinType::ShortAccum: + case BuiltinType::UShortAccum: + case BuiltinType::SatShortAccum: + case BuiltinType::SatUShortAccum: + return 4; + case BuiltinType::Accum: + case BuiltinType::UAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatUAccum: + return 5; + case BuiltinType::LongAccum: + case BuiltinType::ULongAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatULongAccum: + return 6; + default: + if (BTy->isInteger()) + return 0; + llvm_unreachable("Unexpected fixed point or integer type"); + } +} + +/// handleFixedPointConversion - Fixed point operations between fixed +/// point types and integers or other fixed point types do not fall under +/// usual arithmetic conversion since these conversions could result in loss +/// of precsision (N1169 4.1.4). These operations should be calculated with +/// the full precision of their result type (N1169 4.1.6.2.1). +static QualType handleFixedPointConversion(Sema &S, QualType LHSTy, + QualType RHSTy) { + assert((LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) && + "Expected at least one of the operands to be a fixed point type"); + assert((LHSTy->isFixedPointOrIntegerType() || + RHSTy->isFixedPointOrIntegerType()) && + "Special fixed point arithmetic operation conversions are only " + "applied to ints or other fixed point types"); + + // If one operand has signed fixed-point type and the other operand has + // unsigned fixed-point type, then the unsigned fixed-point operand is + // converted to its corresponding signed fixed-point type and the resulting + // type is the type of the converted operand. + if (RHSTy->isSignedFixedPointType() && LHSTy->isUnsignedFixedPointType()) + LHSTy = S.Context.getCorrespondingSignedFixedPointType(LHSTy); + else if (RHSTy->isUnsignedFixedPointType() && LHSTy->isSignedFixedPointType()) + RHSTy = S.Context.getCorrespondingSignedFixedPointType(RHSTy); + + // The result type is the type with the highest rank, whereby a fixed-point + // conversion rank is always greater than an integer conversion rank; if the + // type of either of the operands is a saturating fixedpoint type, the result + // type shall be the saturating fixed-point type corresponding to the type + // with the highest rank; the resulting value is converted (taking into + // account rounding and overflow) to the precision of the resulting type. + // Same ranks between signed and unsigned types are resolved earlier, so both + // types are either signed or both unsigned at this point. + unsigned LHSTyRank = GetFixedPointRank(LHSTy); + unsigned RHSTyRank = GetFixedPointRank(RHSTy); + + QualType ResultTy = LHSTyRank > RHSTyRank ? LHSTy : RHSTy; + + if (LHSTy->isSaturatedFixedPointType() || RHSTy->isSaturatedFixedPointType()) + ResultTy = S.Context.getCorrespondingSaturatedType(ResultTy); + + return ResultTy; +} + /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is @@ -1322,12 +1398,14 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, IsCompAssign); + if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) + return handleFixedPointConversion(*this, LHSType, RHSType); + // Finally, we have two differing integer types. return handleIntegerConversion<doIntegralCast, doIntegralCast> (*this, LHS, RHS, LHSType, RHSType, IsCompAssign); } - //===----------------------------------------------------------------------===// // Semantic Analysis for various Expression Types //===----------------------------------------------------------------------===// @@ -1446,9 +1524,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // If we determined that the generic selection is result-dependent, don't // try to compute the result expression. if (IsResultDependent) - return new (Context) GenericSelectionExpr( - Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, - ContainsUnexpandedParameterPack); + return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, Types, + Exprs, DefaultLoc, RParenLoc, + ContainsUnexpandedParameterPack); SmallVector<unsigned, 1> CompatIndices; unsigned DefaultIndex = -1U; @@ -1499,7 +1577,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, unsigned ResultIndex = CompatIndices.size() ? CompatIndices[0] : DefaultIndex; - return new (Context) GenericSelectionExpr( + return GenericSelectionExpr::Create( Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack, ResultIndex); } @@ -1828,11 +1906,10 @@ static void emitEmptyLookupTypoDiagnostic( /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found -bool -Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, - std::unique_ptr<CorrectionCandidateCallback> CCC, - TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args, TypoExpr **Out) { +bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + CorrectionCandidateCallback &CCC, + TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<Expr *> Args, TypoExpr **Out) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -1921,7 +1998,7 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, assert(!ExplicitTemplateArgs && "Diagnosing an empty lookup with explicit template args!"); *Out = CorrectTypoDelayed( - R.getLookupNameInfo(), R.getLookupKind(), S, &SS, std::move(CCC), + R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, [=](const TypoCorrection &TC) { emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, diagnostic, diagnostic_suggest); @@ -1929,9 +2006,9 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, nullptr, CTK_ErrorRecovery); if (*Out) return true; - } else if (S && (Corrected = - CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, - &SS, std::move(CCC), CTK_ErrorRecovery))) { + } else if (S && + (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), + S, &SS, CCC, CTK_ErrorRecovery))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; @@ -2080,7 +2157,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, - std::unique_ptr<CorrectionCandidateCallback> CCC, + CorrectionCandidateCallback *CCC, bool IsInlineAsmIdentifier, Token *KeywordReplacement) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); @@ -2202,9 +2279,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. TypoExpr *TE = nullptr; - auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>( - II, SS.isValid() ? SS.getScopeRep() : nullptr); - DefaultValidator->IsAddressOfOperand = IsAddressOfOperand; + DefaultFilterCCC DefaultValidator(II, SS.isValid() ? SS.getScopeRep() + : nullptr); + DefaultValidator.IsAddressOfOperand = IsAddressOfOperand; assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) && "Typo correction callback misconfigured"); if (CCC) { @@ -2216,9 +2293,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. - if (DiagnoseEmptyLookup(S, SS, R, - CCC ? std::move(CCC) : std::move(DefaultValidator), - nullptr, None, &TE)) { + if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, + None, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); @@ -2472,8 +2548,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); CXXScopeSpec SelfScopeSpec; SourceLocation TemplateKWLoc; - ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, - SelfName, false, false); + ExprResult SelfExpr = + ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, + /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); if (SelfExpr.isInvalid()) return ExprError(); @@ -2497,11 +2575,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) getCurFunction()->recordUseOfWeak(Result); } - if (getLangOpts().ObjCAutoRefCount) { - if (CurContext->isClosure()) - Diag(Loc, diag::warn_implicitly_retains_self) - << FixItHint::CreateInsertion(Loc, "self->"); - } + if (getLangOpts().ObjCAutoRefCount) + if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) + ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); return Result; } @@ -2572,10 +2648,15 @@ Sema::PerformObjectMemberConversion(Expr *From, bool PointerConversions = false; if (isa<FieldDecl>(Member)) { DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD)); + auto FromPtrType = FromType->getAs<PointerType>(); + DestRecordType = Context.getAddrSpaceQualType( + DestRecordType, FromPtrType + ? FromType->getPointeeType().getAddressSpace() + : FromType.getAddressSpace()); - if (FromType->getAs<PointerType>()) { + if (FromPtrType) { DestType = Context.getPointerType(DestRecordType); - FromRecordType = FromType->getPointeeType(); + FromRecordType = FromPtrType->getPointeeType(); PointerConversions = true; } else { DestType = DestRecordType; @@ -2905,7 +2986,6 @@ ExprResult Sema::BuildDeclarationNameExpr( // These shouldn't make it here. case Decl::ObjCAtDefsField: - case Decl::ObjCIvar: llvm_unreachable("forming non-member reference to ivar?"); // Enum constants are always r-values and never references. @@ -2913,6 +2993,7 @@ ExprResult Sema::BuildDeclarationNameExpr( case Decl::EnumConstant: case Decl::UnresolvedUsingValue: case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: valueKind = VK_RValue; break; @@ -2922,6 +3003,7 @@ ExprResult Sema::BuildDeclarationNameExpr( // exist in the high-level semantics. case Decl::Field: case Decl::IndirectField: + case Decl::ObjCIvar: assert(getLangOpts().CPlusPlus && "building reference to field in C?"); @@ -4810,7 +4892,7 @@ Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, } namespace { -class FunctionCallCCC : public FunctionCallFilterCCC { +class FunctionCallCCC final : public FunctionCallFilterCCC { public: FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName, unsigned NumArgs, MemberExpr *ME) @@ -4826,6 +4908,10 @@ public: return FunctionCallFilterCCC::ValidateCandidate(candidate); } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<FunctionCallCCC>(*this); + } + private: const IdentifierInfo *const FunctionName; }; @@ -4838,11 +4924,10 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, DeclarationName FuncName = FDecl->getDeclName(); SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getBeginLoc(); + FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME); if (TypoCorrection Corrected = S.CorrectTypo( DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName, - S.getScopeForContext(S.CurContext), nullptr, - llvm::make_unique<FunctionCallCCC>(S, FuncName.getAsIdentifierInfo(), - Args.size(), ME), + S.getScopeForContext(S.CurContext), nullptr, CCC, Sema::CTK_ErrorRecovery)) { if (NamedDecl *ND = Corrected.getFoundDecl()) { if (Corrected.isOverloaded()) { @@ -5140,15 +5225,29 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, return; const ConstantArrayType *ArgCAT = - Context.getAsConstantArrayType(ArgExpr->IgnoreParenImpCasts()->getType()); + Context.getAsConstantArrayType(ArgExpr->IgnoreParenCasts()->getType()); if (!ArgCAT) return; - if (ArgCAT->getSize().ult(CAT->getSize())) { + if (getASTContext().hasSameUnqualifiedType(CAT->getElementType(), + ArgCAT->getElementType())) { + if (ArgCAT->getSize().ult(CAT->getSize())) { + Diag(CallLoc, diag::warn_static_array_too_small) + << ArgExpr->getSourceRange() + << (unsigned)ArgCAT->getSize().getZExtValue() + << (unsigned)CAT->getSize().getZExtValue() << 0; + DiagnoseCalleeStaticArrayParam(*this, Param); + } + return; + } + + Optional<CharUnits> ArgSize = + getASTContext().getTypeSizeInCharsIfKnown(ArgCAT); + Optional<CharUnits> ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT); + if (ArgSize && ParmSize && *ArgSize < *ParmSize) { Diag(CallLoc, diag::warn_static_array_too_small) - << ArgExpr->getSourceRange() - << (unsigned) ArgCAT->getSize().getZExtValue() - << (unsigned) CAT->getSize().getZExtValue(); + << ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity() + << (unsigned)ParmSize->getQuantity() << 1; DiagnoseCalleeStaticArrayParam(*this, Param); } } @@ -5690,18 +5789,36 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, } if (!getLangOpts().CPlusPlus) { + // Forget about the nulled arguments since typo correction + // do not handle them well. + TheCall->shrinkNumArgs(Args.size()); // C cannot always handle TypoExpr nodes in builtin calls and direct // function calls as their argument checking don't necessarily handle // dependent types properly, so make sure any TypoExprs have been // dealt with. ExprResult Result = CorrectDelayedTyposInExpr(TheCall); if (!Result.isUsable()) return ExprError(); + CallExpr *TheOldCall = TheCall; TheCall = dyn_cast<CallExpr>(Result.get()); + bool CorrectedTypos = TheCall != TheOldCall; if (!TheCall) return Result; - // TheCall at this point has max(Args.size(), NumParams) arguments, - // with extra arguments nulled. We don't want to introduce nulled - // arguments in Args and so we only take the first Args.size() arguments. - Args = llvm::makeArrayRef(TheCall->getArgs(), Args.size()); + Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); + + // A new call expression node was created if some typos were corrected. + // However it may not have been constructed with enough storage. In this + // case, rebuild the node with enough storage. The waste of space is + // immaterial since this only happens when some typos were corrected. + if (CorrectedTypos && Args.size() < NumParams) { + if (Config) + TheCall = CUDAKernelCallExpr::Create( + Context, Fn, cast<CallExpr>(Config), Args, ResultTy, VK_RValue, + RParenLoc, NumParams); + else + TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue, + RParenLoc, NumParams, UsesADL); + } + // We can now handle the nulled arguments for the default arguments. + TheCall->setNumArgsUnsafe(std::max<unsigned>(Args.size(), NumParams)); } // Bail out early if calling a builtin with custom type checking. @@ -5805,6 +5922,8 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (CheckFunctionCall(FDecl, TheCall, Proto)) return ExprError(); + checkFortifiedBuiltinMemoryFunction(FDecl, TheCall); + if (BuiltinID) return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); } else if (NDecl) { @@ -6031,6 +6150,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { case Type::STK_Bool: return CK_FixedPointToBoolean; case Type::STK_Integral: + return CK_FixedPointToIntegral; case Type::STK_Floating: case Type::STK_IntegralComplex: case Type::STK_FloatingComplex: @@ -6075,10 +6195,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); case Type::STK_FixedPoint: - Diag(Src.get()->getExprLoc(), - diag::err_unimplemented_conversion_with_fixed_point_type) - << SrcTy; - return CK_IntegralCast; + return CK_IntegralToFixedPoint; } llvm_unreachable("Should have returned before this"); @@ -12311,6 +12428,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } } + // Diagnose operations on the unsupported types for OpenMP device compilation. + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { + if (Opc != BO_Assign && Opc != BO_Comma) { + checkOpenMPDeviceExpr(LHSExpr); + checkOpenMPDeviceExpr(RHSExpr); + } + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); @@ -12322,6 +12447,25 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (!ResultTy.isNull()) { DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc); + + // Avoid copying a block to the heap if the block is assigned to a local + // auto variable that is declared in the same scope as the block. This + // optimization is unsafe if the local variable is declared in an outer + // scope. For example: + // + // BlockTy b; + // { + // b = ^{...}; + // } + // // It is unsafe to invoke the block here if it wasn't copied to the + // // heap. + // b(); + + if (auto *BE = dyn_cast<BlockExpr>(RHS.get()->IgnoreParens())) + if (auto *DRE = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens())) + if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (VD->hasLocalStorage() && getCurScope()->isDeclScope(VD)) + BE->getBlockDecl()->setCanAvoidCopyToHeap(); } RecordModifiableNonNullParam(*this, LHS.get()); break; @@ -12887,6 +13031,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, << Input.get()->getSourceRange()); } } + // Diagnose operations on the unsupported types for OpenMP device compilation. + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { + if (UnaryOperator::isIncrementDecrementOp(Opc) || + UnaryOperator::isArithmeticOp(Opc)) + checkOpenMPDeviceExpr(InputExpr); + } + switch (Opc) { case UO_PreInc: case UO_PreDec: @@ -13180,29 +13331,6 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, Context.getPointerType(Context.VoidTy)); } -/// Given the last statement in a statement-expression, check whether -/// the result is a producing expression (like a call to an -/// ns_returns_retained function) and, if so, rebuild it to hoist the -/// release out of the full-expression. Otherwise, return null. -/// Cannot fail. -static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) { - // Should always be wrapped with one of these. - ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement); - if (!cleanups) return nullptr; - - ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr()); - if (!cast || cast->getCastKind() != CK_ARCConsumeObject) - return nullptr; - - // Splice out the cast. This shouldn't modify any interesting - // features of the statement. - Expr *producer = cast->getSubExpr(); - assert(producer->getType() == cast->getType()); - assert(producer->getValueKind() == cast->getValueKind()); - cleanups->setSubExpr(producer); - return cleanups; -} - void Sema::ActOnStartStmtExpr() { PushExpressionEvaluationContext(ExprEvalContexts.back().Context); } @@ -13236,47 +13364,10 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, QualType Ty = Context.VoidTy; bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { - Stmt *LastStmt = Compound->body_back(); - LabelStmt *LastLabelStmt = nullptr; - // If LastStmt is a label, skip down through into the body. - while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) { - LastLabelStmt = Label; - LastStmt = Label->getSubStmt(); - } - - if (Expr *LastE = dyn_cast<Expr>(LastStmt)) { - // Do function/array conversion on the last expression, but not - // lvalue-to-rvalue. However, initialize an unqualified type. - ExprResult LastExpr = DefaultFunctionArrayConversion(LastE); - if (LastExpr.isInvalid()) - return ExprError(); - Ty = LastExpr.get()->getType().getUnqualifiedType(); - - if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) { - // In ARC, if the final expression ends in a consume, splice - // the consume out and bind it later. In the alternate case - // (when dealing with a retainable type), the result - // initialization will create a produce. In both cases the - // result will be +1, and we'll need to balance that out with - // a bind. - if (Expr *rebuiltLastStmt - = maybeRebuildARCConsumingStmt(LastExpr.get())) { - LastExpr = rebuiltLastStmt; - } else { - LastExpr = PerformCopyInitialization( - InitializedEntity::InitializeStmtExprResult(LPLoc, Ty), - SourceLocation(), LastExpr); - } - - if (LastExpr.isInvalid()) - return ExprError(); - if (LastExpr.get() != nullptr) { - if (!LastLabelStmt) - Compound->setLastStmt(LastExpr.get()); - else - LastLabelStmt->setSubStmt(LastExpr.get()); - StmtExprMayBindToTemp = true; - } + if (const auto *LastStmt = dyn_cast<ValueStmt>(Compound->body_back())) { + if (const Expr *Value = LastStmt->getExprStmt()) { + StmtExprMayBindToTemp = true; + Ty = Value->getType(); } } } @@ -13289,6 +13380,37 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, return ResStmtExpr; } +ExprResult Sema::ActOnStmtExprResult(ExprResult ER) { + if (ER.isInvalid()) + return ExprError(); + + // Do function/array conversion on the last expression, but not + // lvalue-to-rvalue. However, initialize an unqualified type. + ER = DefaultFunctionArrayConversion(ER.get()); + if (ER.isInvalid()) + return ExprError(); + Expr *E = ER.get(); + + if (E->isTypeDependent()) + return E; + + // In ARC, if the final expression ends in a consume, splice + // the consume out and bind it later. In the alternate case + // (when dealing with a retainable type), the result + // initialization will create a produce. In both cases the + // result will be +1, and we'll need to balance that out with + // a bind. + auto *Cast = dyn_cast<ImplicitCastExpr>(E); + if (Cast && Cast->getCastKind() == CK_ARCConsumeObject) + return Cast->getSubExpr(); + + // FIXME: Provide a better location for the initialization. + return PerformCopyInitialization( + InitializedEntity::InitializeStmtExprResult( + E->getBeginLoc(), E->getType().getUnqualifiedType()), + SourceLocation(), E); +} + ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef<OffsetOfComponent> Components, @@ -13817,6 +13939,11 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, } } + // NVPTX does not support va_arg expression. + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + Context.getTargetInfo().getTriple().isNVPTX()) + targetDiag(E->getBeginLoc(), diag::err_va_arg_in_device); + // It might be a __builtin_ms_va_list. (But don't ever mark a va_arg() // as Microsoft ABI on an actual Microsoft platform, where // __builtin_ms_va_list and __builtin_va_list are the same.) @@ -14369,14 +14496,6 @@ namespace { // Make sure we redo semantic analysis bool AlwaysRebuild() { return true; } - // Make sure we handle LabelStmts correctly. - // FIXME: This does the right thing, but maybe we need a more general - // fix to TreeTransform? - StmtResult TransformLabelStmt(LabelStmt *S) { - S->getDecl()->setStmt(nullptr); - return BaseTransform::TransformLabelStmt(S); - } - // We need to special-case DeclRefExprs referring to FieldDecls which // are not part of a member pointer formation; normal TreeTransforming // doesn't catch this case because of the way we represent them in the AST. @@ -14676,6 +14795,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) ResolveExceptionSpec(Loc, FPT); + if (getLangOpts().CUDA) + CheckCUDACall(Loc, Func); + // If we don't need to mark the function as used, and we don't need to // try to provide a definition, there's nothing more to do. if ((Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) && @@ -14737,7 +14859,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { - TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind(); + TemplateSpecializationKind TSK = + Func->getTemplateSpecializationKindForInstantiation(); SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); bool FirstInstantiation = PointOfInstantiation.isInvalid(); if (FirstInstantiation) { @@ -14793,6 +14916,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } Func->markUsed(Context); + + if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) + checkOpenMPDeviceFunction(Loc, Func); } static void @@ -15563,7 +15689,12 @@ ExprResult Sema::ActOnConstantExpression(ExprResult Res) { } void Sema::CleanupVarDeclMarking() { - for (Expr *E : MaybeODRUseExprs) { + // Iterate through a local copy in case MarkVarDeclODRUsed makes a recursive + // call. + MaybeODRUseExprSet LocalMaybeODRUseExprs; + std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs); + + for (Expr *E : LocalMaybeODRUseExprs) { VarDecl *Var; SourceLocation Loc; if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { @@ -15580,17 +15711,22 @@ void Sema::CleanupVarDeclMarking() { /*MaxFunctionScopeIndex Pointer*/ nullptr); } - MaybeODRUseExprs.clear(); + assert(MaybeODRUseExprs.empty() && + "MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?"); } - static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E) { assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) && "Invalid Expr argument to DoMarkVarDeclReferenced"); Var->setReferenced(); - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + if (Var->isInvalidDecl()) + return; + + auto *MSI = Var->getMemberSpecializationInfo(); + TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind() + : Var->getTemplateSpecializationKind(); bool OdrUseContext = isOdrUseContext(SemaRef); bool UsableInConstantExpr = @@ -15623,11 +15759,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr); if (TryInstantiating) { - SourceLocation PointOfInstantiation = Var->getPointOfInstantiation(); + SourceLocation PointOfInstantiation = + MSI ? MSI->getPointOfInstantiation() : Var->getPointOfInstantiation(); bool FirstInstantiation = PointOfInstantiation.isInvalid(); if (FirstInstantiation) { PointOfInstantiation = Loc; - Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + if (MSI) + MSI->setPointOfInstantiation(PointOfInstantiation); + else + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); } bool InstantiationDependent = false; @@ -15939,7 +16079,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E, /// behavior of a program, such as passing a non-POD value through an ellipsis. /// Failure to do so will likely result in spurious diagnostics or failures /// during overload resolution or within sizeof/alignof/typeof/typeid. -bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { case ExpressionEvaluationContext::Unevaluated: @@ -15955,9 +16095,9 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, case ExpressionEvaluationContext::PotentiallyEvaluated: case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: - if (Statement && getCurFunctionOrMethodDecl()) { + if (!Stmts.empty() && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. - push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); + push_back(sema::PossiblyUnreachableDiag(PD, Loc, Stmts)); return true; } @@ -15982,6 +16122,12 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, return false; } +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, + const PartialDiagnostic &PD) { + return DiagRuntimeBehavior( + Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD); +} + bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD) { if (ReturnType->isVoidType() || !ReturnType->isIncompleteType()) @@ -16843,10 +16989,9 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( StringRef Platform = getASTContext().getTargetInfo().getPlatformName(); - auto Spec = std::find_if(AvailSpecs.begin(), AvailSpecs.end(), - [&](const AvailabilitySpec &Spec) { - return Spec.getPlatform() == Platform; - }); + auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) { + return Spec.getPlatform() == Platform; + }); VersionTuple Version; if (Spec != AvailSpecs.end()) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 8c89a3cee3..881e0f6546 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1,9 +1,8 @@ //===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -751,12 +750,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && - !getSourceManager().isInSystemHeader(OpLoc) && - (!getLangOpts().OpenMPIsDevice || - !getLangOpts().OpenMPHostCXXExceptions || - isInOpenMPTargetExecutionDirective() || - isInOpenMPDeclareTargetContext())) - Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; + !getSourceManager().isInSystemHeader(OpLoc) && !getLangOpts().CUDA) { + // Delay error emission for the OpenMP device code. + targetDiag(OpLoc, diag::err_exceptions_disabled) << "throw"; + } // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) @@ -1666,7 +1663,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { - Expr *ArraySize = nullptr; + Optional<Expr *> ArraySize; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { @@ -1677,7 +1674,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); - if (!Chunk.Arr.NumElts) + if (!Chunk.Arr.NumElts && !Initializer) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); @@ -1790,7 +1787,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, - Expr *ArraySize, + Optional<Expr *> ArraySize, SourceRange DirectInitRange, Expr *Initializer) { SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); @@ -1841,9 +1838,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, auto *Deduced = AllocType->getContainedDeducedType(); if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) { if (ArraySize) - return ExprError(Diag(ArraySize->getExprLoc(), - diag::err_deduced_class_template_compound_type) - << /*array*/ 2 << ArraySize->getSourceRange()); + return ExprError( + Diag(ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(), + diag::err_deduced_class_template_compound_type) + << /*array*/ 2 + << (ArraySize ? (*ArraySize)->getSourceRange() : TypeRange)); InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); @@ -1873,11 +1872,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (Braced && !getLangOpts().CPlusPlus17) Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init) << AllocType << TypeRange; + Expr *Deduce = Inits[0]; QualType DeducedType; - if (DeduceAutoType(AllocTypeInfo, Inits[0], DeducedType) == DAR_Failed) + if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) - << AllocType << Inits[0]->getType() - << TypeRange << Inits[0]->getSourceRange()); + << AllocType << Deduce->getType() + << TypeRange << Deduce->getSourceRange()); if (DeducedType.isNull()) return ExprError(); AllocType = DeducedType; @@ -1908,8 +1908,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, QualType ResultType = Context.getPointerType(AllocType); - if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(ArraySize); + if (ArraySize && *ArraySize && + (*ArraySize)->getType()->isNonOverloadPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(*ArraySize); if (result.isInvalid()) return ExprError(); ArraySize = result.get(); } @@ -1921,19 +1922,19 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. llvm::Optional<uint64_t> KnownArraySize; - if (ArraySize && !ArraySize->isTypeDependent()) { + if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); - ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), + ConvertedSize = PerformImplicitConversion(*ArraySize, Context.getSizeType(), AA_Converting); if (!ConvertedSize.isInvalid() && - ArraySize->getType()->getAs<RecordType>()) + (*ArraySize)->getType()->getAs<RecordType>()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) - << ArraySize->getType() << 0 << "'size_t'"; + << (*ArraySize)->getType() << 0 << "'size_t'"; } else { class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: @@ -1987,16 +1988,16 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, : diag::ext_array_size_conversion) << T << ConvTy->isEnumeralType() << ConvTy; } - } SizeDiagnoser(ArraySize); + } SizeDiagnoser(*ArraySize); - ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize, + ConvertedSize = PerformContextualImplicitConversion(StartLoc, *ArraySize, SizeDiagnoser); } if (ConvertedSize.isInvalid()) return ExprError(); ArraySize = ConvertedSize.get(); - QualType SizeType = ArraySize->getType(); + QualType SizeType = (*ArraySize)->getType(); if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); @@ -2008,18 +2009,18 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // Let's see if this is a constant < 0. If so, we reject it out of hand, // per CWG1464. Otherwise, if it's not a constant, we must have an // unparenthesized array type. - if (!ArraySize->isValueDependent()) { + if (!(*ArraySize)->isValueDependent()) { llvm::APSInt Value; // We've already performed any required implicit conversion to integer or // unscoped enumeration type. // FIXME: Per CWG1464, we are required to check the value prior to // converting to size_t. This will never find a negative array size in // C++14 onwards, because Value is always unsigned here! - if (ArraySize->isIntegerConstantExpr(Value, Context)) { + if ((*ArraySize)->isIntegerConstantExpr(Value, Context)) { if (Value.isSigned() && Value.isNegative()) { - return ExprError(Diag(ArraySize->getBeginLoc(), + return ExprError(Diag((*ArraySize)->getBeginLoc(), diag::err_typecheck_negative_array_size) - << ArraySize->getSourceRange()); + << (*ArraySize)->getSourceRange()); } if (!AllocType->isDependentType()) { @@ -2027,15 +2028,15 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) return ExprError( - Diag(ArraySize->getBeginLoc(), diag::err_array_too_large) - << Value.toString(10) << ArraySize->getSourceRange()); + Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large) + << Value.toString(10) << (*ArraySize)->getSourceRange()); } KnownArraySize = Value.getZExtValue(); } else if (TypeIdParens.isValid()) { // Can't have dynamic array size when the type-id is in parentheses. - Diag(ArraySize->getBeginLoc(), diag::ext_new_paren_array_nonconst) - << ArraySize->getSourceRange() + Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst) + << (*ArraySize)->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); @@ -2058,10 +2059,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && - FindAllocationFunctions(StartLoc, - SourceRange(PlacementLParen, PlacementRParen), - Scope, Scope, AllocType, ArraySize, PassAlignment, - PlacementArgs, OperatorNew, OperatorDelete)) + FindAllocationFunctions( + StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope, + AllocType, ArraySize.hasValue(), PassAlignment, PlacementArgs, + OperatorNew, OperatorDelete)) return ExprError(); // If this is an array allocation, compute whether the usual array @@ -2154,6 +2155,22 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, FullInit = Binder->getSubExpr(); Initializer = FullInit.get(); + + // FIXME: If we have a KnownArraySize, check that the array bound of the + // initializer is no greater than that constant value. + + if (ArraySize && !*ArraySize) { + auto *CAT = Context.getAsConstantArrayType(Initializer->getType()); + if (CAT) { + // FIXME: Track that the array size was inferred rather than explicitly + // specified. + ArraySize = IntegerLiteral::Create( + Context, CAT->getSize(), Context.getSizeType(), TypeRange.getEnd()); + } else { + Diag(TypeRange.getEnd(), diag::err_new_array_size_unknown_from_init) + << Initializer->getSourceRange(); + } + } } // Mark the new and delete operators as referenced. @@ -2303,8 +2320,8 @@ static bool resolveAllocationOverload( } if (Diagnose) { - S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) - << R.getLookupName() << Range; + PartialDiagnosticAt PD(R.getNameLoc(), S.PDiag(diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range); // If we have aligned candidates, only note the align_val_t candidates // from AlignedCandidates and the non-align_val_t candidates from @@ -2319,31 +2336,34 @@ static bool resolveAllocationOverload( // This was an overaligned allocation, so list the aligned candidates // first. Args.insert(Args.begin() + 1, AlignArg); - AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "", + AlignedCandidates->NoteCandidates(PD, S, OCD_AllCandidates, Args, "", R.getNameLoc(), IsAligned); Args.erase(Args.begin() + 1); - Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), + Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args, "", R.getNameLoc(), IsUnaligned); } else { - Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args); } } return true; case OR_Ambiguous: if (Diagnose) { - S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) - << R.getLookupName() << Range; - Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); + Candidates.NoteCandidates( + PartialDiagnosticAt(R.getNameLoc(), + S.PDiag(diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range), + S, OCD_ViableCandidates, Args); } return true; case OR_Deleted: { if (Diagnose) { - S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) - << Best->Function->isDeleted() << R.getLookupName() - << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; - Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + Candidates.NoteCandidates( + PartialDiagnosticAt(R.getNameLoc(), + S.PDiag(diag::err_ovl_deleted_call) + << R.getLookupName() << Range), + S, OCD_AllCandidates, Args); } return true; } @@ -2798,7 +2818,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, } } - FunctionProtoType::ExtProtoInfo EPI; + FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/false)); QualType BadAllocType; bool HasBadAllocExceptionSpec @@ -3506,22 +3527,26 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, } case OR_No_Viable_Function: - S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) - << R.getLookupName() << Range; - Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + Candidates.NoteCandidates( + PartialDiagnosticAt(R.getNameLoc(), + S.PDiag(diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range), + S, OCD_AllCandidates, Args); return true; case OR_Ambiguous: - S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) - << R.getLookupName() << Range; - Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); + Candidates.NoteCandidates( + PartialDiagnosticAt(R.getNameLoc(), + S.PDiag(diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range), + S, OCD_ViableCandidates, Args); return true; case OR_Deleted: { - S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) - << Best->Function->isDeleted() << R.getLookupName() - << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; - Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + Candidates.NoteCandidates( + PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call) + << R.getLookupName() << Range), + S, OCD_AllCandidates, Args); return true; } } @@ -6855,8 +6880,9 @@ canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef, QualType DestructedType) { // If this is a record type, check if its destructor is callable. if (auto *RD = DestructedType->getAsCXXRecordDecl()) { - if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD)) - return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false); + if (RD->hasDefinition()) + if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD)) + return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false); return false; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index b2b21ba9ee..b07bba5584 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1,9 +1,8 @@ //===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -591,7 +590,7 @@ namespace { // Callback to only accept typo corrections that are either a ValueDecl or a // FunctionTemplateDecl and are declared in the current record or, for a C++ // classes, one of its base classes. -class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { +class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback { public: explicit RecordMemberExprValidatorCCC(const RecordType *RTy) : Record(RTy->getDecl()) { @@ -629,6 +628,10 @@ public: return false; } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<RecordMemberExprValidatorCCC>(*this); + } + private: const RecordDecl *const Record; }; @@ -697,9 +700,9 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, }; QueryState Q = {R.getSema(), R.getLookupNameInfo(), R.getLookupKind(), R.redeclarationKind()}; + RecordMemberExprValidatorCCC CCC(RTy); TE = SemaRef.CorrectTypoDelayed( - R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, - llvm::make_unique<RecordMemberExprValidatorCCC>(RTy), + R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, CCC, [=, &SemaRef](const TypoCorrection &TC) { if (TC) { assert(!TC.isKeyword() && @@ -1332,11 +1335,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (!IV) { // Attempt to correct for typos in ivar names. - auto Validator = llvm::make_unique<DeclFilterCCC<ObjCIvarDecl>>(); - Validator->IsObjCIvarLookup = IsArrow; + DeclFilterCCC<ObjCIvarDecl> Validator{}; + Validator.IsObjCIvarLookup = IsArrow; if (TypoCorrection Corrected = S.CorrectTypo( R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr, - std::move(Validator), Sema::CTK_ErrorRecovery, IDecl)) { + Validator, Sema::CTK_ErrorRecovery, IDecl)) { IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>(); S.diagnoseTypo( Corrected, diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index ed780efd4c..818a981b49 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1,9 +1,8 @@ //===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -26,6 +25,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ConvertUTF.h" using namespace clang; using namespace sema; @@ -525,6 +525,30 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { NSStringPointer = Context.getObjCObjectPointerType(NSStringObject); } + // The boxed expression can be emitted as a compile time constant if it is + // a string literal whose character encoding is compatible with UTF-8. + if (auto *CE = dyn_cast<ImplicitCastExpr>(ValueExpr)) + if (CE->getCastKind() == CK_ArrayToPointerDecay) + if (auto *SL = + dyn_cast<StringLiteral>(CE->getSubExpr()->IgnoreParens())) { + assert((SL->isAscii() || SL->isUTF8()) && + "unexpected character encoding"); + StringRef Str = SL->getString(); + const llvm::UTF8 *StrBegin = Str.bytes_begin(); + const llvm::UTF8 *StrEnd = Str.bytes_end(); + // Check that this is a valid UTF-8 string. + if (llvm::isLegalUTF8String(&StrBegin, StrEnd)) { + BoxedType = Context.getAttributedType( + AttributedType::getNullabilityAttrKind( + NullabilityKind::NonNull), + NSStringPointer, NSStringPointer); + return new (Context) ObjCBoxedExpr(CE, BoxedType, nullptr, SR); + } + + Diag(SL->getBeginLoc(), diag::warn_objc_boxing_invalid_utf8_string) + << NSStringPointer << SL->getSourceRange(); + } + if (!StringWithUTF8StringMethod) { IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String"); Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II); @@ -1922,11 +1946,10 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Attempt to correct for typos in property names. - if (TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(MemberName, MemberLoc), - LookupOrdinaryName, nullptr, nullptr, - llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(), - CTK_ErrorRecovery, IFace, false, OPT)) { + DeclFilterCCC<ObjCPropertyDecl> CCC{}; + if (TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, + nullptr, nullptr, CCC, CTK_ErrorRecovery, IFace, false, OPT)) { DeclarationName TypoResult = Corrected.getCorrection(); if (TypoResult.isIdentifier() && TypoResult.getAsIdentifierInfo() == Member) { @@ -2083,7 +2106,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, namespace { -class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback { +class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback { public: ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) { // Determine whether "super" is acceptable in the current context. @@ -2095,6 +2118,10 @@ class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback { return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() || candidate.isKeyword("super"); } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<ObjCInterfaceOrSuperCCC>(*this); + } }; } // end anonymous namespace @@ -2170,9 +2197,9 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } } + ObjCInterfaceOrSuperCCC CCC(getCurMethodDecl()); if (TypoCorrection Corrected = CorrectTypo( - Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, - llvm::make_unique<ObjCInterfaceOrSuperCCC>(getCurMethodDecl()), + Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, CCC, CTK_ErrorRecovery, nullptr, false, nullptr, false)) { if (Corrected.isKeyword()) { // If we've found the keyword "super" (the only keyword that would be @@ -2806,8 +2833,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } else { if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { - // FIXME: Is this correct? Why are we assuming that a message to - // Class will call a method in the current interface? + // As a guess, try looking for the method in the current interface. + // This very well may not produce the "right" method. // First check the public methods in the class interface. Method = ClassDecl->lookupClassMethod(Sel); @@ -2815,8 +2842,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) Method = ClassDecl->lookupPrivateClassMethod(Sel); - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, nullptr, - false, false, ClassDecl)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } } @@ -4333,23 +4359,22 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { assert(!gse->isResultDependent()); unsigned n = gse->getNumAssocs(); - SmallVector<Expr*, 4> subExprs(n); - SmallVector<TypeSourceInfo*, 4> subTypes(n); - for (unsigned i = 0; i != n; ++i) { - subTypes[i] = gse->getAssocTypeSourceInfo(i); - Expr *sub = gse->getAssocExpr(i); - if (i == gse->getResultIndex()) + SmallVector<Expr *, 4> subExprs; + SmallVector<TypeSourceInfo *, 4> subTypes; + subExprs.reserve(n); + subTypes.reserve(n); + for (const GenericSelectionExpr::Association &assoc : gse->associations()) { + subTypes.push_back(assoc.getTypeSourceInfo()); + Expr *sub = assoc.getAssociationExpr(); + if (assoc.isSelected()) sub = stripARCUnbridgedCast(sub); - subExprs[i] = sub; + subExprs.push_back(sub); } - return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(), - gse->getControllingExpr(), - subTypes, subExprs, - gse->getDefaultLoc(), - gse->getRParenLoc(), - gse->containsUnexpandedParameterPack(), - gse->getResultIndex()); + return GenericSelectionExpr::Create( + Context, gse->getGenericLoc(), gse->getControllingExpr(), subTypes, + subExprs, gse->getDefaultLoc(), gse->getRParenLoc(), + gse->containsUnexpandedParameterPack(), gse->getResultIndex()); } else { assert(isa<ImplicitCastExpr>(e) && "bad form of unbridged cast!"); return cast<ImplicitCastExpr>(e)->getSubExpr(); diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp index 714fbedf09..41a7a90a37 100644 --- a/lib/Sema/SemaFixItUtils.cpp +++ b/lib/Sema/SemaFixItUtils.cpp @@ -1,9 +1,8 @@ //===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 10c0c6bf33..e8a8887736 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1,9 +1,8 @@ //===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -145,16 +144,43 @@ static StringInitFailureKind IsStringInit(Expr *init, QualType declType, static void updateStringLiteralType(Expr *E, QualType Ty) { while (true) { E->setType(Ty); - if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) + E->setValueKind(VK_RValue); + if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) { break; - else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) + } else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { E = PE->getSubExpr(); - else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) + } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + assert(UO->getOpcode() == UO_Extension); E = UO->getSubExpr(); - else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) + } else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) { E = GSE->getResultExpr(); - else + } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) { + E = CE->getChosenSubExpr(); + } else { llvm_unreachable("unexpected expr in string literal init"); + } + } +} + +/// Fix a compound literal initializing an array so it's correctly marked +/// as an rvalue. +static void updateGNUCompoundLiteralRValue(Expr *E) { + while (true) { + E->setValueKind(VK_RValue); + if (isa<CompoundLiteralExpr>(E)) { + break; + } else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + assert(UO->getOpcode() == UO_Extension); + E = UO->getSubExpr(); + } else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) { + E = GSE->getResultExpr(); + } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) { + E = CE->getChosenSubExpr(); + } else { + llvm_unreachable("unexpected expr in array compound literal init"); + } } } @@ -2182,7 +2208,7 @@ namespace { // Callback to only accept typo corrections that are for field members of // the given struct or union. -class FieldInitializerValidatorCCC : public CorrectionCandidateCallback { +class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback { public: explicit FieldInitializerValidatorCCC(RecordDecl *RD) : Record(RD) {} @@ -2192,6 +2218,10 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback { return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record); } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<FieldInitializerValidatorCCC>(*this); + } + private: RecordDecl *Record; }; @@ -2394,10 +2424,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Name lookup didn't find anything. // Determine whether this was a typo for another field name. + FieldInitializerValidatorCCC CCC(RT->getDecl()); if (TypoCorrection Corrected = SemaRef.CorrectTypo( DeclarationNameInfo(FieldName, D->getFieldLoc()), - Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, - llvm::make_unique<FieldInitializerValidatorCCC>(RT->getDecl()), + Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, CCC, Sema::CTK_ErrorRecovery, RT->getDecl())) { SemaRef.diagnoseTypo( Corrected, @@ -4671,19 +4701,23 @@ static void TryReferenceInitializationCore(Sema &S, // applied. // Postpone address space conversions to after the temporary materialization // conversion to allow creating temporaries in the alloca address space. - auto AS1 = T1Quals.getAddressSpace(); - auto AS2 = T2Quals.getAddressSpace(); - T1Quals.removeAddressSpace(); - T2Quals.removeAddressSpace(); - QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1Quals); - if (T1Quals != T2Quals) + auto T1QualsIgnoreAS = T1Quals; + auto T2QualsIgnoreAS = T2Quals; + if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) { + T1QualsIgnoreAS.removeAddressSpace(); + T2QualsIgnoreAS.removeAddressSpace(); + } + QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1QualsIgnoreAS); + if (T1QualsIgnoreAS != T2QualsIgnoreAS) Sequence.AddQualificationConversionStep(cv1T4, ValueKind); Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_RValue); ValueKind = isLValueRef ? VK_LValue : VK_XValue; - if (AS1 != AS2) { - T1Quals.addAddressSpace(AS1); - QualType cv1AST4 = S.Context.getQualifiedType(cv2T2, T1Quals); - Sequence.AddQualificationConversionStep(cv1AST4, ValueKind); + // Add addr space conversion if required. + if (T1Quals.getAddressSpace() != T2Quals.getAddressSpace()) { + auto T4Quals = cv1T4.getQualifiers(); + T4Quals.addAddressSpace(T1Quals.getAddressSpace()); + QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals); + Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind); } // In any case, the reference is bound to the resulting glvalue (or to @@ -4730,7 +4764,15 @@ static void TryReferenceInitializationCore(Sema &S, // copy-initialization (8.5). The reference is then bound to the // temporary. [...] - InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); + // Ignore address space of reference type at this point and perform address + // space conversion after the reference binding step. + QualType cv1T1IgnoreAS = + T1Quals.hasAddressSpace() + ? S.Context.getQualifiedType(T1, T1Quals.withoutAddressSpace()) + : cv1T1; + + InitializedEntity TempEntity = + InitializedEntity::InitializeTemporary(cv1T1IgnoreAS); // FIXME: Why do we use an implicit conversion here rather than trying // copy-initialization? @@ -4765,8 +4807,9 @@ static void TryReferenceInitializationCore(Sema &S, // than, cv2; otherwise, the program is ill-formed. unsigned T1CVRQuals = T1Quals.getCVRQualifiers(); unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); - if (RefRelationship == Sema::Ref_Related && - (T1CVRQuals | T2CVRQuals) != T1CVRQuals) { + if ((RefRelationship == Sema::Ref_Related && + (T1CVRQuals | T2CVRQuals) != T1CVRQuals) || + !T1Quals.isAddressSpaceSupersetOf(T2Quals)) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } @@ -4780,7 +4823,11 @@ static void TryReferenceInitializationCore(Sema &S, return; } - Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*bindingTemporary=*/true); + + if (T1Quals.hasAddressSpace()) + Sequence.AddQualificationConversionStep(cv1T1, isLValueRef ? VK_LValue + : VK_XValue); } /// Attempt character array initialization from a string literal @@ -5538,8 +5585,7 @@ void InitializationSequence::InitializeFrom(Sema &S, // array from a compound literal that creates an array of the same // type, so long as the initializer has no side effects. if (!S.getLangOpts().CPlusPlus && Initializer && - (isa<ConstantExpr>(Initializer->IgnoreParens()) || - isa<CompoundLiteralExpr>(Initializer->IgnoreParens())) && + isa<CompoundLiteralExpr>(Initializer->IgnoreParens()) && Initializer->getType()->isArrayType()) { const ArrayType *SourceAT = Context.getAsArrayType(Initializer->getType()); @@ -5925,21 +5971,25 @@ static ExprResult CopyObject(Sema &S, break; case OR_No_Viable_Function: - S.Diag(Loc, IsExtraneousCopy && !S.isSFINAEContext() - ? diag::ext_rvalue_to_reference_temp_copy_no_viable - : diag::err_temp_copy_no_viable) - << (int)Entity.getKind() << CurInitExpr->getType() - << CurInitExpr->getSourceRange(); - CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr); + CandidateSet.NoteCandidates( + PartialDiagnosticAt( + Loc, S.PDiag(IsExtraneousCopy && !S.isSFINAEContext() + ? diag::ext_rvalue_to_reference_temp_copy_no_viable + : diag::err_temp_copy_no_viable) + << (int)Entity.getKind() << CurInitExpr->getType() + << CurInitExpr->getSourceRange()), + S, OCD_AllCandidates, CurInitExpr); if (!IsExtraneousCopy || S.isSFINAEContext()) return ExprError(); return CurInit; case OR_Ambiguous: - S.Diag(Loc, diag::err_temp_copy_ambiguous) - << (int)Entity.getKind() << CurInitExpr->getType() - << CurInitExpr->getSourceRange(); - CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(Loc, S.PDiag(diag::err_temp_copy_ambiguous) + << (int)Entity.getKind() + << CurInitExpr->getType() + << CurInitExpr->getSourceRange()), + S, OCD_ViableCandidates, CurInitExpr); return ExprError(); case OR_Deleted: @@ -6074,13 +6124,13 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, break; case OR_No_Viable_Function: - S.Diag(Loc, Diag); - CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr); + CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S, + OCD_AllCandidates, CurInitExpr); break; case OR_Ambiguous: - S.Diag(Loc, Diag); - CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr); + CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S, + OCD_ViableCandidates, CurInitExpr); break; case OR_Deleted: @@ -7275,9 +7325,19 @@ ExprResult Sema::TemporaryMaterializationConversion(Expr *E) { ExprResult Sema::PerformQualificationConversion(Expr *E, QualType Ty, ExprValueKind VK, CheckedConversionKind CCK) { - CastKind CK = (Ty.getAddressSpace() != E->getType().getAddressSpace()) - ? CK_AddressSpaceConversion - : CK_NoOp; + + CastKind CK = CK_NoOp; + + if (VK == VK_RValue) { + auto PointeeTy = Ty->getPointeeType(); + auto ExprPointeeTy = E->getType()->getPointeeType(); + if (!PointeeTy.isNull() && + PointeeTy.getAddressSpace() != ExprPointeeTy.getAddressSpace()) + CK = CK_AddressSpaceConversion; + } else if (Ty.getAddressSpace() != E->getType().getAddressSpace()) { + CK = CK_AddressSpaceConversion; + } + return ImpCastExprToType(E, Ty, CK, VK, /*BasePath=*/nullptr, CCK); } @@ -7952,6 +8012,7 @@ ExprResult InitializationSequence::Perform(Sema &S, S.Diag(Kind.getLocation(), diag::ext_array_init_copy) << Step->Type << CurInit.get()->getType() << CurInit.get()->getSourceRange(); + updateGNUCompoundLiteralRValue(CurInit.get()); LLVM_FALLTHROUGH; case SK_ArrayInit: // If the destination type is an incomplete array type, update the @@ -8342,19 +8403,22 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_UserConversionOverloadFailed: switch (FailedOverloadResult) { case OR_Ambiguous: - if (Failure == FK_UserConversionOverloadFailed) - S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) - << OnlyArg->getType() << DestType - << Args[0]->getSourceRange(); - else - S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous) - << DestType << OnlyArg->getType() - << Args[0]->getSourceRange(); - FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); + FailedCandidateSet.NoteCandidates( + PartialDiagnosticAt( + Kind.getLocation(), + Failure == FK_UserConversionOverloadFailed + ? (S.PDiag(diag::err_typecheck_ambiguous_condition) + << OnlyArg->getType() << DestType + << Args[0]->getSourceRange()) + : (S.PDiag(diag::err_ref_init_ambiguous) + << DestType << OnlyArg->getType() + << Args[0]->getSourceRange())), + S, OCD_ViableCandidates, Args); break; - case OR_No_Viable_Function: + case OR_No_Viable_Function: { + auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args); if (!S.RequireCompleteType(Kind.getLocation(), DestType.getNonReferenceType(), diag::err_typecheck_nonviable_condition_incomplete, @@ -8364,9 +8428,9 @@ bool InitializationSequence::Diagnose(Sema &S, << OnlyArg->getType() << Args[0]->getSourceRange() << DestType.getNonReferenceType(); - FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); + FailedCandidateSet.NoteCandidates(S, Args, Cands); break; - + } case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) << OnlyArg->getType() << DestType.getNonReferenceType() @@ -8451,6 +8515,7 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ReferenceInitFailed: S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) << DestType.getNonReferenceType() + << DestType.getNonReferenceType()->isIncompleteType() << OnlyArg->isLValue() << OnlyArg->getType() << Args[0]->getSourceRange(); @@ -8529,9 +8594,11 @@ bool InitializationSequence::Diagnose(Sema &S, // bad. switch (FailedOverloadResult) { case OR_Ambiguous: - S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) - << DestType << ArgsRange; - FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); + FailedCandidateSet.NoteCandidates( + PartialDiagnosticAt(Kind.getLocation(), + S.PDiag(diag::err_ovl_ambiguous_init) + << DestType << ArgsRange), + S, OCD_ViableCandidates, Args); break; case OR_No_Viable_Function: @@ -8580,9 +8647,12 @@ bool InitializationSequence::Diagnose(Sema &S, break; } - S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) - << DestType << ArgsRange; - FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); + FailedCandidateSet.NoteCandidates( + PartialDiagnosticAt( + Kind.getLocation(), + S.PDiag(diag::err_ovl_no_viable_function_in_init) + << DestType << ArgsRange), + S, OCD_AllCandidates, Args); break; case OR_Deleted: { @@ -8591,7 +8661,7 @@ bool InitializationSequence::Diagnose(Sema &S, = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); if (Ovl != OR_Deleted) { S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) - << true << DestType << ArgsRange; + << DestType << ArgsRange; llvm_unreachable("Inconsistent overload resolution?"); break; } @@ -8605,7 +8675,7 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << ArgsRange; else S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) - << true << DestType << ArgsRange; + << DestType << ArgsRange; S.NoteDeletedFunction(Best->Function); break; @@ -9264,9 +9334,14 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( OverloadCandidateSet Candidates(Kind.getLocation(), OverloadCandidateSet::CSK_Normal); OverloadCandidateSet::iterator Best; + + bool HasAnyDeductionGuide = false; + auto tryToResolveOverload = [&](bool OnlyListConstructors) -> OverloadingResult { Candidates.clear(OverloadCandidateSet::CSK_Normal); + HasAnyDeductionGuide = false; + for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); if (D->isInvalidDecl()) @@ -9278,6 +9353,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( if (!GD) continue; + if (!GD->isImplicit()) + HasAnyDeductionGuide = true; + // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class) // For copy-initialization, the candidate functions are all the // converting constructors (12.3.1) of that class. @@ -9372,12 +9450,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( switch (Result) { case OR_Ambiguous: - Diag(Kind.getLocation(), diag::err_deduced_class_template_ctor_ambiguous) - << TemplateName; // FIXME: For list-initialization candidates, it'd usually be better to // list why they were not viable when given the initializer list itself as // an argument. - Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits); + Candidates.NoteCandidates( + PartialDiagnosticAt( + Kind.getLocation(), + PDiag(diag::err_deduced_class_template_ctor_ambiguous) + << TemplateName), + *this, OCD_ViableCandidates, Inits); return QualType(); case OR_No_Viable_Function: { @@ -9385,11 +9466,13 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( cast<ClassTemplateDecl>(Template)->getTemplatedDecl(); bool Complete = isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary)); - Diag(Kind.getLocation(), - Complete ? diag::err_deduced_class_template_ctor_no_viable - : diag::err_deduced_class_template_incomplete) - << TemplateName << !Guides.empty(); - Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits); + Candidates.NoteCandidates( + PartialDiagnosticAt( + Kind.getLocation(), + PDiag(Complete ? diag::err_deduced_class_template_ctor_no_viable + : diag::err_deduced_class_template_incomplete) + << TemplateName << !Guides.empty()), + *this, OCD_AllCandidates, Inits); return QualType(); } @@ -9430,5 +9513,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType; + + // Warn if CTAD was used on a type that does not have any user-defined + // deduction guides. + if (!HasAnyDeductionGuide) { + Diag(TSInfo->getTypeLoc().getBeginLoc(), + diag::warn_ctad_maybe_unsupported) + << TemplateName; + Diag(Template->getLocation(), diag::note_suppress_ctad_maybe_unsupported); + } + return DeducedType; } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index af233b96d6..b686681f04 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1,9 +1,8 @@ //===--- SemaLambda.cpp - Semantic Analysis for C++11 Lambdas -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -21,6 +20,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; using namespace sema; @@ -226,19 +226,14 @@ Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda( static inline TemplateParameterList * getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) { - if (LSI->GLTemplateParameterList) - return LSI->GLTemplateParameterList; - - if (!LSI->AutoTemplateParams.empty()) { - SourceRange IntroRange = LSI->IntroducerRange; - SourceLocation LAngleLoc = IntroRange.getBegin(); - SourceLocation RAngleLoc = IntroRange.getEnd(); + if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) { LSI->GLTemplateParameterList = TemplateParameterList::Create( SemaRef.Context, - /*Template kw loc*/ SourceLocation(), LAngleLoc, - llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(), - LSI->AutoTemplateParams.size()), - RAngleLoc, nullptr); + /*Template kw loc*/ SourceLocation(), + /*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(), + LSI->TemplateParams, + /*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(), + nullptr); } return LSI->GLTemplateParameterList; } @@ -493,6 +488,23 @@ void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { LSI->finishedExplicitCaptures(); } +void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> TParams, + SourceLocation RAngleLoc) { + LambdaScopeInfo *LSI = getCurLambda(); + assert(LSI && "Expected a lambda scope"); + assert(LSI->NumExplicitTemplateParams == 0 && + "Already acted on explicit template parameters"); + assert(LSI->TemplateParams.empty() && + "Explicit template parameters should come " + "before invented (auto) ones"); + assert(!TParams.empty() && + "No template parameters to act on"); + LSI->TemplateParams.append(TParams.begin(), TParams.end()); + LSI->NumExplicitTemplateParams = TParams.size(); + LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc}; +} + void Sema::addLambdaParameters( ArrayRef<LambdaIntroducer::LambdaCapture> Captures, CXXMethodDecl *CallOperator, Scope *CurScope) { @@ -759,15 +771,14 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc, TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType); // Deduce the type of the init capture. - Expr *DeduceInit = Init; QualType DeducedType = deduceVarTypeFromInitializer( /*VarDecl*/nullptr, DeclarationName(Id), DeductType, TSI, - SourceRange(Loc, Loc), IsDirectInit, DeduceInit); + SourceRange(Loc, Loc), IsDirectInit, Init); if (DeducedType.isNull()) return QualType(); // Are we a non-list direct initialization? - bool CXXDirectInit = isa<ParenListExpr>(Init); + ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // Perform initialization analysis and ensure any implicit conversions // (such as lvalue-to-rvalue) are enforced. @@ -780,7 +791,10 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc, : InitializationKind::CreateDirectList(Loc)) : InitializationKind::CreateCopy(Loc, Init->getBeginLoc()); - MultiExprArg Args = DeduceInit; + MultiExprArg Args = Init; + if (CXXDirectInit) + Args = + MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs()); QualType DclT; InitializationSequence InitSeq(*this, Entity, Kind, Args); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); @@ -831,17 +845,23 @@ FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) { void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { - // Determine if we're within a context where we know that the lambda will - // be dependent, because there are template parameters in scope. - bool KnownDependent = false; LambdaScopeInfo *const LSI = getCurLambda(); assert(LSI && "LambdaScopeInfo should be on stack!"); - // The lambda-expression's closure type might be dependent even if its - // semantic context isn't, if it appears within a default argument of a - // function template. - if (CurScope->getTemplateParamParent()) - KnownDependent = true; + // Determine if we're within a context where we know that the lambda will + // be dependent, because there are template parameters in scope. + bool KnownDependent; + if (LSI->NumExplicitTemplateParams > 0) { + auto *TemplateParamScope = CurScope->getTemplateParamParent(); + assert(TemplateParamScope && + "Lambda with explicit template param list should establish a " + "template param scope"); + assert(TemplateParamScope->getParent()); + KnownDependent = TemplateParamScope->getParent() + ->getTemplateParamParent() != nullptr; + } else { + KnownDependent = CurScope->getTemplateParamParent() != nullptr; + } // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; @@ -1080,8 +1100,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (R.empty()) { // FIXME: Disable corrections that would add qualification? CXXScopeSpec ScopeSpec; - if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, - llvm::make_unique<DeclFilterCCC<VarDecl>>())) + DeclFilterCCC<VarDecl> Validator{}; + if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator)) continue; } @@ -1228,9 +1248,10 @@ static void addFunctionPointerConversion(Sema &S, FunctionProtoType::ExtProtoInfo ConvExtInfo( S.Context.getDefaultCallingConvention( /*IsVariadic=*/false, /*IsCXXMethod=*/true)); - // The conversion function is always const. + // The conversion function is always const and noexcept. ConvExtInfo.TypeQuals = Qualifiers(); ConvExtInfo.TypeQuals.addConst(); + ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept; QualType ConvTy = S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index effccc2f3d..2b7924d244 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1,9 +1,8 @@ //===--------------------- SemaLookup.cpp - Name Lookup ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -279,6 +278,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_OMPReduction; break; + case Sema::LookupOMPMapperName: + IDNS = Decl::IDNS_OMPMapper; + break; + case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol @@ -1540,8 +1543,21 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. bool VisibleWithinParent; - if (D->isTemplateParameter() || isa<ParmVarDecl>(D) || - (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) + if (D->isTemplateParameter()) { + bool SearchDefinitions = true; + if (const auto *DCD = dyn_cast<Decl>(DC)) { + if (const auto *TD = DCD->getDescribedTemplate()) { + TemplateParameterList *TPL = TD->getTemplateParameters(); + auto Index = getDepthAndIndex(D).second; + SearchDefinitions = Index >= TPL->size() || TPL->getParam(Index) != D; + } + } + if (SearchDefinitions) + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); + else + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); + } else if (isa<ParmVarDecl>(D) || + (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); else if (D->isModulePrivate()) { // A module-private declaration is only visible if an enclosing lexical @@ -2104,6 +2120,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, BaseCallback = &CXXRecordDecl::FindOMPReductionMember; break; + case LookupOMPMapperName: + BaseCallback = &CXXRecordDecl::FindOMPMapperMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. @@ -2165,11 +2185,27 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin(); DeclContext::lookup_iterator CurrentD = Path->Decls.begin(); + // Get the decl that we should use for deduplicating this lookup. + auto GetRepresentativeDecl = [&](NamedDecl *D) -> Decl * { + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in + // an ambiguity in certain cases (for example, if it is found in + // more than one base class). If all of the injected-class-names + // that are found refer to specializations of the same class + // template, and if the name is used as a template-name, the + // reference refers to the class template itself and not a + // specialization thereof, and is not ambiguous. + if (R.isTemplateNameLookup()) + if (auto *TD = getAsTemplateNameDecl(D)) + D = TD; + return D->getUnderlyingDecl()->getCanonicalDecl(); + }; + while (FirstD != FirstPath->Decls.end() && CurrentD != Path->Decls.end()) { - if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != - (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) - break; + if (GetRepresentativeDecl(*FirstD) != + GetRepresentativeDecl(*CurrentD)) + break; ++FirstD; ++CurrentD; @@ -2417,40 +2453,56 @@ namespace { InstantiationLoc(InstantiationLoc) { } + bool addClassTransitive(CXXRecordDecl *RD) { + Classes.insert(RD); + return ClassesTransitive.insert(RD); + } + Sema &S; Sema::AssociatedNamespaceSet &Namespaces; Sema::AssociatedClassSet &Classes; SourceLocation InstantiationLoc; + + private: + Sema::AssociatedClassSet ClassesTransitive; }; } // end anonymous namespace static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType T); +// Given the declaration context \param Ctx of a class, class template or +// enumeration, add the associated namespaces to \param Namespaces as described +// in [basic.lookup.argdep]p2. static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, DeclContext *Ctx) { - // Add the associated namespace for this class. - - // We don't use DeclContext::getEnclosingNamespaceContext() as this may - // be a locally scoped record. + // The exact wording has been changed in C++14 as a result of + // CWG 1691 (see also CWG 1690 and CWG 1692). We apply it unconditionally + // to all language versions since it is possible to return a local type + // from a lambda in C++11. + // + // C++14 [basic.lookup.argdep]p2: + // If T is a class type [...]. Its associated namespaces are the innermost + // enclosing namespaces of its associated classes. [...] + // + // If T is an enumeration type, its associated namespace is the innermost + // enclosing namespace of its declaration. [...] - // We skip out of inline namespaces. The innermost non-inline namespace + // We additionally skip inline namespaces. The innermost non-inline namespace // contains all names of all its nested inline namespaces anyway, so we can // replace the entire inline namespace tree with its root. - while (Ctx->isRecord() || Ctx->isTransparentContext() || - Ctx->isInlineNamespace()) + while (!Ctx->isFileContext() || Ctx->isInlineNamespace()) Ctx = Ctx->getParent(); - if (Ctx->isFileContext()) - Namespaces.insert(Ctx->getPrimaryContext()); + Namespaces.insert(Ctx->getPrimaryContext()); } // Add the associated classes and namespaces for argument-dependent -// lookup that involves a template argument (C++ [basic.lookup.koenig]p2). +// lookup that involves a template argument (C++ [basic.lookup.argdep]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, const TemplateArgument &Arg) { - // C++ [basic.lookup.koenig]p2, last bullet: + // C++ [basic.lookup.argdep]p2, last bullet: // -- [...] ; switch (Arg.getKind()) { case TemplateArgument::Null: @@ -2495,9 +2547,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } } -// Add the associated classes and namespaces for -// argument-dependent lookup with an argument of class type -// (C++ [basic.lookup.koenig]p2). +// Add the associated classes and namespaces for argument-dependent lookup +// with an argument of class type (C++ [basic.lookup.argdep]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, CXXRecordDecl *Class) { @@ -2506,30 +2557,22 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, if (Class->getDeclName() == Result.S.VAListTagName) return; - // C++ [basic.lookup.koenig]p2: + // C++ [basic.lookup.argdep]p2: // [...] // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a - // member, if any; and its direct and indirect base - // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. + // member, if any; and its direct and indirect base classes. + // Its associated namespaces are the innermost enclosing + // namespaces of its associated classes. // Add the class of which it is a member, if any. DeclContext *Ctx = Class->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) Result.Classes.insert(EnclosingClass); + // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); - // Add the class itself. If we've already seen this class, we don't - // need to visit base classes. - // - // FIXME: That's not correct, we may have added this class only because it - // was the enclosing class of another class, and in that case we won't have - // added its base classes yet. - if (!Result.Classes.insert(Class)) - return; - // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member // templates, the member template's class; the namespaces and classes @@ -2552,6 +2595,11 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, addAssociatedClassesAndNamespaces(Result, TemplateArgs[I]); } + // Add the class itself. If we've already transitively visited this class, + // we don't need to visit base classes. + if (!Result.addClassTransitive(Class)) + return; + // Only recurse into base classes for complete types. if (!Result.S.isCompleteType(Result.InstantiationLoc, Result.S.Context.getRecordType(Class))) @@ -2577,7 +2625,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, if (!BaseType) continue; CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (Result.Classes.insert(BaseDecl)) { + if (Result.addClassTransitive(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); CollectEnclosingNamespace(Result.Namespaces, BaseCtx); @@ -2642,10 +2690,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { break; // -- If T is a class type (including unions), its associated - // classes are: the class itself; the class of which it is a - // member, if any; and its direct and indirect base - // classes. Its associated namespaces are the namespaces in - // which its associated classes are defined. + // classes are: the class itself; the class of which it is + // a member, if any; and its direct and indirect base classes. + // Its associated namespaces are the innermost enclosing + // namespaces of its associated classes. case Type::Record: { CXXRecordDecl *Class = cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl()); @@ -2653,10 +2701,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { break; } - // -- If T is an enumeration type, its associated namespace is - // the namespace in which it is defined. If it is class - // member, its associated class is the member's class; else - // it has no associated class. + // -- If T is an enumeration type, its associated namespace + // is the innermost enclosing namespace of its declaration. + // If it is a class member, its associated class is the + // member’s class; else it has no associated class. case Type::Enum: { EnumDecl *Enum = cast<EnumType>(T)->getDecl(); @@ -2664,7 +2712,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) Result.Classes.insert(EnclosingClass); - // Add the associated namespace for this class. + // Add the associated namespace for this enumeration. CollectEnclosingNamespace(Result.Namespaces, Ctx); break; @@ -2793,15 +2841,9 @@ void Sema::FindAssociatedClassesAndNamespaces( // in which the function or function template is defined and the // classes and namespaces associated with its (non-dependent) // parameter types and return type. - Arg = Arg->IgnoreParens(); - if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) - if (unaryOp->getOpcode() == UO_AddrOf) - Arg = unaryOp->getSubExpr(); + OverloadExpr *OE = OverloadExpr::find(Arg).Expression; - UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg); - if (!ULE) continue; - - for (const auto *D : ULE->decls()) { + for (const NamedDecl *D : OE->decls()) { // Look through any using declarations to find the underlying function. const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction(); @@ -4317,9 +4359,8 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( SpecifierOStream.flush(); SameNameSpecifier = NewNameSpecifier == CurNameSpecifier; } - if (SameNameSpecifier || - std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), - Name) != CurContextIdentifiers.end()) { + if (SameNameSpecifier || llvm::find(CurContextIdentifiers, Name) != + CurContextIdentifiers.end()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = @@ -4551,8 +4592,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef, std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, - std::unique_ptr<CorrectionCandidateCallback> CCC, + Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery) { @@ -4614,9 +4654,13 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( TypoName.getBeginLoc()); } - CorrectionCandidateCallback &CCCRef = *CCC; + // Extend the lifetime of the callback. We delayed this until here + // to avoid allocations in the hot path (which is where no typo correction + // occurs). Note that CorrectionCandidateCallback is polymorphic and + // initially stack-allocated. + std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone(); auto Consumer = llvm::make_unique<TypoCorrectionConsumer>( - *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, + *this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext, EnteringContext); // Perform name lookup to find visible, similarly-named entities. @@ -4668,7 +4712,9 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( } } - AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty()); + AddKeywordsToConsumer(*this, *Consumer, S, + *Consumer->getCorrectionValidator(), + SS && SS->isNotEmpty()); // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going // to search those namespaces. @@ -4722,19 +4768,18 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, - std::unique_ptr<CorrectionCandidateCallback> CCC, + CorrectionCandidateCallback &CCC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool RecordFailure) { - assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback"); - // Always let the ExternalSource have the first chance at correction, even // if we would otherwise have given up. if (ExternalSource) { - if (TypoCorrection Correction = ExternalSource->CorrectTypo( - TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT)) + if (TypoCorrection Correction = + ExternalSource->CorrectTypo(TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, OPT)) return Correction; } @@ -4742,12 +4787,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for // some instances of CTC_Unknown, while WantRemainingKeywords is true // for CTC_Unknown but not for CTC_ObjCMessageReceiver. - bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords; + bool ObjCMessageReceiver = CCC.WantObjCSuper && !CCC.WantRemainingKeywords; IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); - auto Consumer = makeTypoCorrectionConsumer( - TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, - EnteringContext, OPT, Mode == CTK_ErrorRecovery); + auto Consumer = makeTypoCorrectionConsumer(TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, + OPT, Mode == CTK_ErrorRecovery); if (!Consumer) return TypoCorrection(); @@ -4857,16 +4902,13 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, /// needed. TypoExpr *Sema::CorrectTypoDelayed( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, - std::unique_ptr<CorrectionCandidateCallback> CCC, + Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) { - assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); - - auto Consumer = makeTypoCorrectionConsumer( - TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, - EnteringContext, OPT, Mode == CTK_ErrorRecovery); + auto Consumer = makeTypoCorrectionConsumer(TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, + OPT, Mode == CTK_ErrorRecovery); // Give the external sema source a chance to correct the typo. TypoCorrection ExternalTypo; @@ -5052,7 +5094,7 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, auto Merged = Context.getModulesWithMergedDefinition(Def); OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end()); - diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK, + diagnoseMissingImport(Loc, Def, Def->getLocation(), OwningModules, MIK, Recover); } @@ -5072,12 +5114,58 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, MissingImportKind MIK, bool Recover) { assert(!Modules.empty()); + auto NotePrevious = [&] { + unsigned DiagID; + switch (MIK) { + case MissingImportKind::Declaration: + DiagID = diag::note_previous_declaration; + break; + case MissingImportKind::Definition: + DiagID = diag::note_previous_definition; + break; + case MissingImportKind::DefaultArgument: + DiagID = diag::note_default_argument_declared_here; + break; + case MissingImportKind::ExplicitSpecialization: + DiagID = diag::note_explicit_specialization_declared_here; + break; + case MissingImportKind::PartialSpecialization: + DiagID = diag::note_partial_specialization_declared_here; + break; + } + Diag(DeclLoc, DiagID); + }; + // Weed out duplicates from module list. llvm::SmallVector<Module*, 8> UniqueModules; llvm::SmallDenseSet<Module*, 8> UniqueModuleSet; - for (auto *M : Modules) + for (auto *M : Modules) { + if (M->Kind == Module::GlobalModuleFragment) + continue; if (UniqueModuleSet.insert(M).second) UniqueModules.push_back(M); + } + + if (UniqueModules.empty()) { + // All candidates were global module fragments. Try to suggest a #include. + const FileEntry *E = + PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, Modules[0], DeclLoc); + // FIXME: Find a smart place to suggest inserting a #include, and add + // a FixItHint there. + Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment) + << (int)MIK << Decl << !!E + << (E ? getIncludeStringForHeader(PP, E) : ""); + // Produce a "previous" note if it will point to a header rather than some + // random global module fragment. + // FIXME: Suppress the note backtrace even under + // -fdiagnostics-show-note-include-stack. + if (E) + NotePrevious(); + if (Recover) + createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]); + return; + } + Modules = UniqueModules; if (Modules.size() > 1) { @@ -5110,25 +5198,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, << (int)MIK << Decl << Modules[0]->getFullModuleName(); } - unsigned DiagID; - switch (MIK) { - case MissingImportKind::Declaration: - DiagID = diag::note_previous_declaration; - break; - case MissingImportKind::Definition: - DiagID = diag::note_previous_definition; - break; - case MissingImportKind::DefaultArgument: - DiagID = diag::note_default_argument_declared_here; - break; - case MissingImportKind::ExplicitSpecialization: - DiagID = diag::note_explicit_specialization_declared_here; - break; - case MissingImportKind::PartialSpecialization: - DiagID = diag::note_partial_specialization_declared_here; - break; - } - Diag(DeclLoc, DiagID); + NotePrevious(); // Try to recover by implicitly importing this module. if (Recover) diff --git a/lib/Sema/SemaModule.cpp b/lib/Sema/SemaModule.cpp new file mode 100644 index 0000000000..68c2286cf4 --- /dev/null +++ b/lib/Sema/SemaModule.cpp @@ -0,0 +1,710 @@ +//===--- SemaModule.cpp - Semantic Analysis for Modules -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for modules (C++ modules syntax, +// Objective-C modules syntax, and Clang header modules). +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/SemaInternal.h" + +using namespace clang; +using namespace sema; + +static void checkModuleImportContext(Sema &S, Module *M, + SourceLocation ImportLoc, DeclContext *DC, + bool FromInclude = false) { + SourceLocation ExternCLoc; + + if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) { + switch (LSD->getLanguage()) { + case LinkageSpecDecl::lang_c: + if (ExternCLoc.isInvalid()) + ExternCLoc = LSD->getBeginLoc(); + break; + case LinkageSpecDecl::lang_cxx: + break; + } + DC = LSD->getParent(); + } + + while (isa<LinkageSpecDecl>(DC) || isa<ExportDecl>(DC)) + DC = DC->getParent(); + + if (!isa<TranslationUnitDecl>(DC)) { + S.Diag(ImportLoc, (FromInclude && S.isModuleVisible(M)) + ? diag::ext_module_import_not_at_top_level_noop + : diag::err_module_import_not_at_top_level_fatal) + << M->getFullModuleName() << DC; + S.Diag(cast<Decl>(DC)->getBeginLoc(), + diag::note_module_import_not_at_top_level) + << DC; + } else if (!M->IsExternC && ExternCLoc.isValid()) { + S.Diag(ImportLoc, diag::ext_module_import_in_extern_c) + << M->getFullModuleName(); + S.Diag(ExternCLoc, diag::note_extern_c_begins_here); + } +} + +Sema::DeclGroupPtrTy +Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) { + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) { + // Under -std=c++2a -fmodules-ts, we can find an explicit 'module;' after + // already implicitly entering the global module fragment. That's OK. + assert(getLangOpts().CPlusPlusModules && getLangOpts().ModulesTS && + "unexpectedly encountered multiple global module fragment decls"); + ModuleScopes.back().BeginLoc = ModuleLoc; + return nullptr; + } + + // We start in the global module; all those declarations are implicitly + // module-private (though they do not have module linkage). + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + auto *GlobalModule = Map.createGlobalModuleFragmentForModuleUnit(ModuleLoc); + assert(GlobalModule && "module creation should not fail"); + + // Enter the scope of the global module. + ModuleScopes.push_back({}); + ModuleScopes.back().BeginLoc = ModuleLoc; + ModuleScopes.back().Module = GlobalModule; + VisibleModules.setVisible(GlobalModule, ModuleLoc); + + // All declarations created from now on are owned by the global module. + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible); + TU->setLocalOwningModule(GlobalModule); + + // FIXME: Consider creating an explicit representation of this declaration. + return nullptr; +} + +Sema::DeclGroupPtrTy +Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, + ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) { + assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) && + "should only have module decl in Modules TS or C++20"); + + // A module implementation unit requires that we are not compiling a module + // of any kind. A module interface unit requires that we are not compiling a + // module map. + switch (getLangOpts().getCompilingModule()) { + case LangOptions::CMK_None: + // It's OK to compile a module interface as a normal translation unit. + break; + + case LangOptions::CMK_ModuleInterface: + if (MDK != ModuleDeclKind::Implementation) + break; + + // We were asked to compile a module interface unit but this is a module + // implementation unit. That indicates the 'export' is missing. + Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch) + << FixItHint::CreateInsertion(ModuleLoc, "export "); + MDK = ModuleDeclKind::Interface; + break; + + case LangOptions::CMK_ModuleMap: + Diag(ModuleLoc, diag::err_module_decl_in_module_map_module); + return nullptr; + + case LangOptions::CMK_HeaderModule: + Diag(ModuleLoc, diag::err_module_decl_in_header_module); + return nullptr; + } + + assert(ModuleScopes.size() <= 1 && "expected to be at global module scope"); + + // FIXME: Most of this work should be done by the preprocessor rather than + // here, in order to support macro import. + + // Only one module-declaration is permitted per source file. + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->isModulePurview()) { + Diag(ModuleLoc, diag::err_module_redeclaration); + Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module), + diag::note_prev_module_declaration); + return nullptr; + } + + // Find the global module fragment we're adopting into this module, if any. + Module *GlobalModuleFragment = nullptr; + if (!ModuleScopes.empty() && + ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) + GlobalModuleFragment = ModuleScopes.back().Module; + + // In C++20, the module-declaration must be the first declaration if there + // is no global module fragment. + if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !GlobalModuleFragment) { + Diag(ModuleLoc, diag::err_module_decl_not_at_start); + SourceLocation BeginLoc = + ModuleScopes.empty() + ? SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()) + : ModuleScopes.back().BeginLoc; + if (BeginLoc.isValid()) { + Diag(BeginLoc, diag::note_global_module_introducer_missing) + << FixItHint::CreateInsertion(BeginLoc, "module;\n"); + } + } + + // Flatten the dots in a module name. Unlike Clang's hierarchical module map + // modules, the dots here are just another character that can appear in a + // module name. + std::string ModuleName; + for (auto &Piece : Path) { + if (!ModuleName.empty()) + ModuleName += "."; + ModuleName += Piece.first->getName(); + } + + // If a module name was explicitly specified on the command line, it must be + // correct. + if (!getLangOpts().CurrentModule.empty() && + getLangOpts().CurrentModule != ModuleName) { + Diag(Path.front().second, diag::err_current_module_name_mismatch) + << SourceRange(Path.front().second, Path.back().second) + << getLangOpts().CurrentModule; + return nullptr; + } + const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; + + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + Module *Mod; + + switch (MDK) { + case ModuleDeclKind::Interface: { + // We can't have parsed or imported a definition of this module or parsed a + // module map defining it already. + if (auto *M = Map.findModule(ModuleName)) { + Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; + if (M->DefinitionLoc.isValid()) + Diag(M->DefinitionLoc, diag::note_prev_module_definition); + else if (const auto *FE = M->getASTFile()) + Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) + << FE->getName(); + Mod = M; + break; + } + + // Create a Module for the module that we're defining. + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, + GlobalModuleFragment); + assert(Mod && "module creation should not fail"); + break; + } + + case ModuleDeclKind::Implementation: + std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( + PP.getIdentifierInfo(ModuleName), Path[0].second); + Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, + Module::AllVisible, + /*IsIncludeDirective=*/false); + if (!Mod) { + Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; + // Create an empty module interface unit for error recovery. + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, + GlobalModuleFragment); + } + break; + } + + if (!GlobalModuleFragment) { + ModuleScopes.push_back({}); + if (getLangOpts().ModulesLocalVisibility) + ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + } else { + // We're done with the global module fragment now. + ActOnEndOfTranslationUnitFragment(TUFragmentKind::Global); + } + + // Switch from the global module fragment (if any) to the named module. + ModuleScopes.back().BeginLoc = StartLoc; + ModuleScopes.back().Module = Mod; + ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation; + VisibleModules.setVisible(Mod, ModuleLoc); + + // From now on, we have an owning module for all declarations we see. + // However, those declarations are module-private unless explicitly + // exported. + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + TU->setLocalOwningModule(Mod); + + // FIXME: Create a ModuleDecl. + return nullptr; +} + +Sema::DeclGroupPtrTy +Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, + SourceLocation PrivateLoc) { + // C++20 [basic.link]/2: + // A private-module-fragment shall appear only in a primary module + // interface unit. + switch (ModuleScopes.empty() ? Module::GlobalModuleFragment + : ModuleScopes.back().Module->Kind) { + case Module::ModuleMapModule: + case Module::GlobalModuleFragment: + Diag(PrivateLoc, diag::err_private_module_fragment_not_module); + return nullptr; + + case Module::PrivateModuleFragment: + Diag(PrivateLoc, diag::err_private_module_fragment_redefined); + Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition); + return nullptr; + + case Module::ModuleInterfaceUnit: + break; + } + + if (!ModuleScopes.back().ModuleInterface) { + Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface); + Diag(ModuleScopes.back().BeginLoc, + diag::note_not_module_interface_add_export) + << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); + return nullptr; + } + + // FIXME: Check this isn't a module interface partition. + // FIXME: Check that this translation unit does not import any partitions; + // such imports would violate [basic.link]/2's "shall be the only module unit" + // restriction. + + // We've finished the public fragment of the translation unit. + ActOnEndOfTranslationUnitFragment(TUFragmentKind::Normal); + + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + Module *PrivateModuleFragment = + Map.createPrivateModuleFragmentForInterfaceUnit( + ModuleScopes.back().Module, PrivateLoc); + assert(PrivateModuleFragment && "module creation should not fail"); + + // Enter the scope of the private module fragment. + ModuleScopes.push_back({}); + ModuleScopes.back().BeginLoc = ModuleLoc; + ModuleScopes.back().Module = PrivateModuleFragment; + ModuleScopes.back().ModuleInterface = true; + VisibleModules.setVisible(PrivateModuleFragment, ModuleLoc); + + // All declarations created from now on are scoped to the private module + // fragment (and are neither visible nor reachable in importers of the module + // interface). + auto *TU = Context.getTranslationUnitDecl(); + TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); + TU->setLocalOwningModule(PrivateModuleFragment); + + // FIXME: Consider creating an explicit representation of this declaration. + return nullptr; +} + +DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, + SourceLocation ExportLoc, + SourceLocation ImportLoc, + ModuleIdPath Path) { + // Flatten the module path for a Modules TS module name. + std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc; + if (getLangOpts().ModulesTS) { + std::string ModuleName; + for (auto &Piece : Path) { + if (!ModuleName.empty()) + ModuleName += "."; + ModuleName += Piece.first->getName(); + } + ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; + Path = ModuleIdPath(ModuleNameLoc); + } + + Module *Mod = + getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, + /*IsIncludeDirective=*/false); + if (!Mod) + return true; + + return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path); +} + +/// Determine whether \p D is lexically within an export-declaration. +static const ExportDecl *getEnclosingExportDecl(const Decl *D) { + for (auto *DC = D->getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) + if (auto *ED = dyn_cast<ExportDecl>(DC)) + return ED; + return nullptr; +} + +DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, + SourceLocation ExportLoc, + SourceLocation ImportLoc, + Module *Mod, ModuleIdPath Path) { + VisibleModules.setVisible(Mod, ImportLoc); + + checkModuleImportContext(*this, Mod, ImportLoc, CurContext); + + // FIXME: we should support importing a submodule within a different submodule + // of the same top-level module. Until we do, make it an error rather than + // silently ignoring the import. + // Import-from-implementation is valid in the Modules TS. FIXME: Should we + // warn on a redundant import of the current module? + // FIXME: Import of a module from an implementation partition of the same + // module is permitted. + if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && + (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) { + Diag(ImportLoc, getLangOpts().isCompilingModule() + ? diag::err_module_self_import + : diag::err_module_import_in_implementation) + << Mod->getFullModuleName() << getLangOpts().CurrentModule; + } + + SmallVector<SourceLocation, 2> IdentifierLocs; + Module *ModCheck = Mod; + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + // If we've run out of module parents, just drop the remaining identifiers. + // We need the length to be consistent. + if (!ModCheck) + break; + ModCheck = ModCheck->Parent; + + IdentifierLocs.push_back(Path[I].second); + } + + // If this was a header import, pad out with dummy locations. + // FIXME: Pass in and use the location of the header-name token in this case. + if (Path.empty()) { + for (; ModCheck; ModCheck = ModCheck->Parent) { + IdentifierLocs.push_back(SourceLocation()); + } + } + + ImportDecl *Import = ImportDecl::Create(Context, CurContext, StartLoc, + Mod, IdentifierLocs); + CurContext->addDecl(Import); + + // Sequence initialization of the imported module before that of the current + // module, if any. + if (!ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, Import); + + // Re-export the module if needed. + if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) { + if (ExportLoc.isValid() || getEnclosingExportDecl(Import)) + getCurrentModule()->Exports.emplace_back(Mod, false); + } else if (ExportLoc.isValid()) { + Diag(ExportLoc, diag::err_export_not_in_module_interface); + } + + return Import; +} + +void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { + checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); + BuildModuleInclude(DirectiveLoc, Mod); +} + +void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { + // Determine whether we're in the #include buffer for a module. The #includes + // in that buffer do not qualify as module imports; they're just an + // implementation detail of us building the module. + // + // FIXME: Should we even get ActOnModuleInclude calls for those? + bool IsInModuleIncludes = + TUKind == TU_Module && + getSourceManager().isWrittenInMainFile(DirectiveLoc); + + bool ShouldAddImport = !IsInModuleIncludes; + + // If this module import was due to an inclusion directive, create an + // implicit import declaration to capture it in the AST. + if (ShouldAddImport) { + TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); + ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, + DirectiveLoc, Mod, + DirectiveLoc); + if (!ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, ImportD); + TU->addDecl(ImportD); + Consumer.HandleImplicitImportDecl(ImportD); + } + + getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc); + VisibleModules.setVisible(Mod, DirectiveLoc); +} + +void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { + checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); + + ModuleScopes.push_back({}); + ModuleScopes.back().Module = Mod; + if (getLangOpts().ModulesLocalVisibility) + ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + + VisibleModules.setVisible(Mod, DirectiveLoc); + + // The enclosing context is now part of this module. + // FIXME: Consider creating a child DeclContext to hold the entities + // lexically within the module. + if (getLangOpts().trackLocalOwningModule()) { + for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) { + cast<Decl>(DC)->setModuleOwnershipKind( + getLangOpts().ModulesLocalVisibility + ? Decl::ModuleOwnershipKind::VisibleWhenImported + : Decl::ModuleOwnershipKind::Visible); + cast<Decl>(DC)->setLocalOwningModule(Mod); + } + } +} + +void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { + if (getLangOpts().ModulesLocalVisibility) { + VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules); + // Leaving a module hides namespace names, so our visible namespace cache + // is now out of date. + VisibleNamespaceCache.clear(); + } + + assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod && + "left the wrong module scope"); + ModuleScopes.pop_back(); + + // We got to the end of processing a local module. Create an + // ImportDecl as we would for an imported module. + FileID File = getSourceManager().getFileID(EomLoc); + SourceLocation DirectiveLoc; + if (EomLoc == getSourceManager().getLocForEndOfFile(File)) { + // We reached the end of a #included module header. Use the #include loc. + assert(File != getSourceManager().getMainFileID() && + "end of submodule in main source file"); + DirectiveLoc = getSourceManager().getIncludeLoc(File); + } else { + // We reached an EOM pragma. Use the pragma location. + DirectiveLoc = EomLoc; + } + BuildModuleInclude(DirectiveLoc, Mod); + + // Any further declarations are in whatever module we returned to. + if (getLangOpts().trackLocalOwningModule()) { + // The parser guarantees that this is the same context that we entered + // the module within. + for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) { + cast<Decl>(DC)->setLocalOwningModule(getCurrentModule()); + if (!getCurrentModule()) + cast<Decl>(DC)->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::Unowned); + } + } +} + +void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, + Module *Mod) { + // Bail if we're not allowed to implicitly import a module here. + if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery || + VisibleModules.isVisible(Mod)) + return; + + // Create the implicit import declaration. + TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); + ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, + Loc, Mod, Loc); + TU->addDecl(ImportD); + Consumer.HandleImplicitImportDecl(ImportD); + + // Make the module visible. + getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc); + VisibleModules.setVisible(Mod, Loc); +} + +/// We have parsed the start of an export declaration, including the '{' +/// (if present). +Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, + SourceLocation LBraceLoc) { + ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc); + + // Set this temporarily so we know the export-declaration was braced. + D->setRBraceLoc(LBraceLoc); + + // C++2a [module.interface]p1: + // An export-declaration shall appear only [...] in the purview of a module + // interface unit. An export-declaration shall not appear directly or + // indirectly within [...] a private-module-fragment. + if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) { + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; + } else if (!ModuleScopes.back().ModuleInterface) { + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1; + Diag(ModuleScopes.back().BeginLoc, + diag::note_not_module_interface_add_export) + << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); + } else if (ModuleScopes.back().Module->Kind == + Module::PrivateModuleFragment) { + Diag(ExportLoc, diag::err_export_in_private_module_fragment); + Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment); + } + + for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) { + if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) { + // An export-declaration shall not appear directly or indirectly within + // an unnamed namespace [...] + if (ND->isAnonymousNamespace()) { + Diag(ExportLoc, diag::err_export_within_anonymous_namespace); + Diag(ND->getLocation(), diag::note_anonymous_namespace); + // Don't diagnose internal-linkage declarations in this region. + D->setInvalidDecl(); + break; + } + + // A declaration is exported if it is [...] a namespace-definition + // that contains an exported declaration. + // + // Defer exporting the namespace until after we leave it, in order to + // avoid marking all subsequent declarations in the namespace as exported. + if (!DeferredExportedNamespaces.insert(ND).second) + break; + } + } + + // [...] its declaration or declaration-seq shall not contain an + // export-declaration. + if (auto *ED = getEnclosingExportDecl(D)) { + Diag(ExportLoc, diag::err_export_within_export); + if (ED->hasBraces()) + Diag(ED->getLocation(), diag::note_export); + } + + CurContext->addDecl(D); + PushDeclContext(S, D); + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); + return D; +} + +static bool checkExportedDeclContext(Sema &S, DeclContext *DC, + SourceLocation BlockStart); + +namespace { +enum class UnnamedDeclKind { + Empty, + StaticAssert, + Asm, + UsingDirective, + Context +}; +} + +static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) { + if (isa<EmptyDecl>(D)) + return UnnamedDeclKind::Empty; + if (isa<StaticAssertDecl>(D)) + return UnnamedDeclKind::StaticAssert; + if (isa<FileScopeAsmDecl>(D)) + return UnnamedDeclKind::Asm; + if (isa<UsingDirectiveDecl>(D)) + return UnnamedDeclKind::UsingDirective; + // Everything else either introduces one or more names or is ill-formed. + return llvm::None; +} + +unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { + switch (UDK) { + case UnnamedDeclKind::Empty: + case UnnamedDeclKind::StaticAssert: + // Allow empty-declarations and static_asserts in an export block as an + // extension. + return InBlock ? diag::ext_export_no_name_block : diag::err_export_no_name; + + case UnnamedDeclKind::UsingDirective: + // Allow exporting using-directives as an extension. + return diag::ext_export_using_directive; + + case UnnamedDeclKind::Context: + // Allow exporting DeclContexts that transitively contain no declarations + // as an extension. + return diag::ext_export_no_names; + + case UnnamedDeclKind::Asm: + return diag::err_export_no_name; + } + llvm_unreachable("unknown kind"); +} + +static void diagExportedUnnamedDecl(Sema &S, UnnamedDeclKind UDK, Decl *D, + SourceLocation BlockStart) { + S.Diag(D->getLocation(), getUnnamedDeclDiag(UDK, BlockStart.isValid())) + << (unsigned)UDK; + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); +} + +/// Check that it's valid to export \p D. +static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { + // C++2a [module.interface]p3: + // An exported declaration shall declare at least one name + if (auto UDK = getUnnamedDeclKind(D)) + diagExportedUnnamedDecl(S, *UDK, D, BlockStart); + + // [...] shall not declare a name with internal linkage. + if (auto *ND = dyn_cast<NamedDecl>(D)) { + // Don't diagnose anonymous union objects; we'll diagnose their members + // instead. + if (ND->getDeclName() && ND->getFormalLinkage() == InternalLinkage) { + S.Diag(ND->getLocation(), diag::err_export_internal) << ND; + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); + } + } + + // C++2a [module.interface]p5: + // all entities to which all of the using-declarators ultimately refer + // shall have been introduced with a name having external linkage + if (auto *USD = dyn_cast<UsingShadowDecl>(D)) { + NamedDecl *Target = USD->getUnderlyingDecl(); + if (Target->getFormalLinkage() == InternalLinkage) { + S.Diag(USD->getLocation(), diag::err_export_using_internal) << Target; + S.Diag(Target->getLocation(), diag::note_using_decl_target); + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); + } + } + + // Recurse into namespace-scope DeclContexts. (Only namespace-scope + // declarations are exported.) + if (auto *DC = dyn_cast<DeclContext>(D)) + if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D)) + return checkExportedDeclContext(S, DC, BlockStart); + return false; +} + +/// Check that it's valid to export all the declarations in \p DC. +static bool checkExportedDeclContext(Sema &S, DeclContext *DC, + SourceLocation BlockStart) { + bool AllUnnamed = true; + for (auto *D : DC->decls()) + AllUnnamed &= checkExportedDecl(S, D, BlockStart); + return AllUnnamed; +} + +/// Complete the definition of an export declaration. +Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { + auto *ED = cast<ExportDecl>(D); + if (RBraceLoc.isValid()) + ED->setRBraceLoc(RBraceLoc); + + PopDeclContext(); + + if (!D->isInvalidDecl()) { + SourceLocation BlockStart = + ED->hasBraces() ? ED->getBeginLoc() : SourceLocation(); + for (auto *Child : ED->decls()) { + if (checkExportedDecl(*this, Child, BlockStart)) { + // If a top-level child is a linkage-spec declaration, it might contain + // no declarations (transitively), in which case it's ill-formed. + diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child, + BlockStart); + } + } + } + + return D; +} diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 9412d01600..2521441f8b 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1,9 +1,8 @@ //===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -1943,11 +1942,10 @@ static void DiagnoseUnimplementedAccessor( llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) { // Check to see if we have a corresponding selector in SMap and with the // right method type. - auto I = std::find_if(SMap.begin(), SMap.end(), - [&](const ObjCMethodDecl *x) { - return x->getSelector() == Method && - x->isClassMethod() == Prop->isClassProperty(); - }); + auto I = llvm::find_if(SMap, [&](const ObjCMethodDecl *x) { + return x->getSelector() == Method && + x->isClassMethod() == Prop->isClassProperty(); + }); // When reporting on missing property setter/getter implementation in // categories, do not report when they are declared in primary class, // class's protocol, or one of it super classes. This is because, @@ -2281,9 +2279,18 @@ void Sema::DiagnoseMissingDesignatedInitOverrides( I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) { const ObjCMethodDecl *MD = *I; if (!InitSelSet.count(MD->getSelector())) { + // Don't emit a diagnostic if the overriding method in the subclass is + // marked as unavailable. bool Ignore = false; if (auto *IMD = IFD->getInstanceMethod(MD->getSelector())) { Ignore = IMD->isUnavailable(); + } else { + // Check the methods declared in the class extensions too. + for (auto *Ext : IFD->visible_extensions()) + if (auto *IMD = Ext->getInstanceMethod(MD->getSelector())) { + Ignore = IMD->isUnavailable(); + break; + } } if (!Ignore) { Diag(ImplD->getLocation(), diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 36048a38b9..c6c3a6b590 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1,9 +1,8 @@ //===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file @@ -135,7 +134,7 @@ private: /// get the data (loop counters etc.) about enclosing loop-based construct. /// This data is required during codegen. DoacrossDependMapTy DoacrossDepends; - /// first argument (Expr *) contains optional argument of the + /// First argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion; @@ -148,6 +147,9 @@ private: /// Reference to the taskgroup task_reduction reference expression. Expr *TaskgroupReductionRef = nullptr; llvm::DenseSet<QualType> MappedClassesQualTypes; + /// List of globals marked as declare target link in this target region + /// (isOpenMPTargetExecutionDirective(Directive) == true). + llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), @@ -186,10 +188,31 @@ private: /// Vector of previously declared requires directives SmallVector<const OMPRequiresDecl *, 2> RequiresDecls; + /// omp_allocator_handle_t type. + QualType OMPAllocatorHandleT; + /// Expression for the predefined allocators. + Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = { + nullptr}; + /// Vector of previously encountered target directives + SmallVector<SourceLocation, 2> TargetLocations; public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} + /// Sets omp_allocator_handle_t type. + void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; } + /// Gets omp_allocator_handle_t type. + QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; } + /// Sets the given default allocator. + void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, + Expr *Allocator) { + OMPPredefinedAllocators[AllocatorKind] = Allocator; + } + /// Returns the specified default allocator. + Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const { + return OMPPredefinedAllocators[AllocatorKind]; + } + bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } OpenMPClauseKind getClauseParsingMode() const { assert(isClauseParsingMode() && "Must be in clause parsing mode."); @@ -401,6 +424,16 @@ public: RequiresDecls.push_back(RD); } + /// Checks if the defined 'requires' directive has specified type of clause. + template <typename ClauseType> + bool hasRequiresDeclWithClause() { + return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) { + return llvm::any_of(D->clauselists(), [](const OMPClause *C) { + return isa<ClauseType>(C); + }); + }); + } + /// Checks for a duplicate clause amongst previously declared requires /// directives bool hasDuplicateRequiresClause(ArrayRef<OMPClause *> ClauseList) const { @@ -423,6 +456,16 @@ public: return IsDuplicate; } + /// Add location of previously encountered target to internal vector + void addTargetDirLocation(SourceLocation LocStart) { + TargetLocations.push_back(LocStart); + } + + // Return previously encountered target region locations. + ArrayRef<SourceLocation> getEncounteredTargetLocs() const { + return TargetLocations; + } + /// Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { assert(!isStackEmpty()); @@ -675,6 +718,31 @@ public: return StackElem.MappedClassesQualTypes.count(QT) != 0; } + /// Adds global declare target to the parent target region. + void addToParentTargetRegionLinkGlobals(DeclRefExpr *E) { + assert(*OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( + E->getDecl()) == OMPDeclareTargetDeclAttr::MT_Link && + "Expected declare target link global."); + if (isStackEmpty()) + return; + auto It = Stack.back().first.rbegin(); + while (It != Stack.back().first.rend() && + !isOpenMPTargetExecutionDirective(It->Directive)) + ++It; + if (It != Stack.back().first.rend()) { + assert(isOpenMPTargetExecutionDirective(It->Directive) && + "Expected target executable directive."); + It->DeclareTargetLinkVarDecls.push_back(E); + } + } + + /// Returns the list of globals with declare target link if current directive + /// is target. + ArrayRef<DeclRefExpr *> getLinkGlobals() const { + assert(isOpenMPTargetExecutionDirective(getCurrentDirective()) && + "Expected target executable directive."); + return Stack.back().first.back().DeclareTargetLinkVarDecls; + } }; bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { @@ -682,7 +750,8 @@ bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { } bool isImplicitOrExplicitTaskingRegion(OpenMPDirectiveKind DKind) { - return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || DKind == OMPD_unknown; + return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || + DKind == OMPD_unknown; } } // namespace @@ -1077,7 +1146,7 @@ bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const { return false; TopScope = I->CurScope ? I->CurScope->getParent() : nullptr; Scope *CurScope = getCurScope(); - while (CurScope != TopScope && !CurScope->isDeclScope(D)) + while (CurScope && CurScope != TopScope && !CurScope->isDeclScope(D)) CurScope = CurScope->getParent(); return CurScope != TopScope; } @@ -1394,6 +1463,68 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) { DSAStack->popFunction(OldFSI); } +static bool isOpenMPDeviceDelayedContext(Sema &S) { + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + return !S.isInOpenMPTargetExecutionDirective() && + !S.isInOpenMPDeclareTargetContext(); +} + +/// Do we know that we will eventually codegen the given function? +static bool isKnownEmitted(Sema &S, FunctionDecl *FD) { + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + // Templates are emitted when they're instantiated. + if (FD->isDependentContext()) + return false; + + if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration( + FD->getCanonicalDecl())) + return true; + + // Otherwise, the function is known-emitted if it's in our set of + // known-emitted functions. + return S.DeviceKnownEmittedFns.count(FD) > 0; +} + +Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, + unsigned DiagID) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) && + !isKnownEmitted(*this, getCurFunctionDecl())) + ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate, + Loc, DiagID, getCurFunctionDecl(), *this); +} + +void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + "Expected OpenMP device compilation."); + assert(Callee && "Callee may not be null."); + FunctionDecl *Caller = getCurFunctionDecl(); + + // If the caller is known-emitted, mark the callee as known-emitted. + // Otherwise, mark the call in our call graph so we can traverse it later. + if (!isOpenMPDeviceDelayedContext(*this) || + (Caller && isKnownEmitted(*this, Caller))) + markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted); + else if (Caller) + DeviceCallGraph[Caller].insert({Callee, Loc}); +} + +void Sema::checkOpenMPDeviceExpr(const Expr *E) { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "OpenMP device compilation mode is expected."); + QualType Ty = E->getType(); + if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || + (Ty->isFloat128Type() && !Context.getTargetInfo().hasFloat128Type()) || + (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && + !Context.getTargetInfo().hasInt128Type())) + targetDiag(E->getExprLoc(), diag::err_type_unsupported) + << Ty << E->getSourceRange(); +} + bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); @@ -1647,10 +1778,15 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) { DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); + if (VD && DSAStack->getDefaultDSA() == DSA_none) + return VD; DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; }, DSAStack->isClauseParsingMode()); - if (DVarPrivate.CKind != OMPC_unknown) + // The variable is not private or it is the variable in the directive with + // default(none) clause and not used in any clause. + if (DVarPrivate.CKind != OMPC_unknown || + (VD && DSAStack->getDefaultDSA() == DSA_none)) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } return nullptr; @@ -1764,6 +1900,9 @@ void Sema::EndOpenMPClause() { DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses); + void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a lastprivate @@ -1794,8 +1933,10 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { *this, DE->getExprLoc(), Type.getUnqualifiedType(), VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE); ActOnUninitializedDecl(VDPrivate); - if (VDPrivate->isInvalidDecl()) + if (VDPrivate->isInvalidDecl()) { + PrivateCopies.push_back(nullptr); continue; + } PrivateCopies.push_back(buildDeclRefExpr( *this, VDPrivate, DE->getType(), DE->getExprLoc())); } else { @@ -1804,11 +1945,12 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PrivateCopies.push_back(nullptr); } } - // Set initializers to private copies if no errors were found. - if (PrivateCopies.size() == Clause->varlist_size()) - Clause->setPrivateCopies(PrivateCopies); + Clause->setPrivateCopies(PrivateCopies); } } + // Check allocate clauses. + if (!CurContext->isDependentContext()) + checkAllocateClauses(*this, DSAStack, D->clauses()); } DSAStack->pop(); @@ -1837,6 +1979,11 @@ public: } return false; } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<VarDeclFilterCCC>(*this); + } + }; class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback { @@ -1847,19 +1994,25 @@ public: explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); - if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) { + if (ND && ((isa<VarDecl>(ND) && ND->getKind() == Decl::Var) || + isa<FunctionDecl>(ND))) { return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), SemaRef.getCurScope()); } return false; } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this); + } }; } // namespace ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, - const DeclarationNameInfo &Id) { + const DeclarationNameInfo &Id, + OpenMPDirectiveKind Kind) { LookupResult Lookup(*this, Id, LookupOrdinaryName); LookupParsedName(Lookup, CurScope, &ScopeSpec, true); @@ -1868,9 +2021,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, VarDecl *VD; if (!Lookup.isSingleResult()) { - if (TypoCorrection Corrected = CorrectTypo( - Id, LookupOrdinaryName, CurScope, nullptr, - llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) { + VarDeclFilterCCC CCC(*this); + if (TypoCorrection Corrected = + CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC, + CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(Lookup.empty() ? diag::err_undeclared_var_use_suggest @@ -1892,9 +2046,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Syntax, C/C++] // Variables must be file-scope, namespace-scope, or static block-scope. - if (!VD->hasGlobalStorage()) { + if (Kind == OMPD_threadprivate && !VD->hasGlobalStorage()) { Diag(Id.getLoc(), diag::err_omp_global_var_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal(); + << getOpenMPDirectiveName(Kind) << !VD->isStaticLocal(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1911,7 +2065,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, if (CanonicalVD->getDeclContext()->isTranslationUnit() && !getCurLexicalContext()->isTranslationUnit()) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1926,7 +2080,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, if (CanonicalVD->isStaticDataMember() && !CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1942,7 +2096,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, (!getCurLexicalContext()->isFileContext() || !getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1953,10 +2107,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Restrictions, C/C++, p.6] // A threadprivate directive for static block-scope variables must appear // in the scope of the variable and not in a nested scope. - if (CanonicalVD->isStaticLocal() && CurScope && + if (CanonicalVD->isLocalVarDecl() && CurScope && !isDeclInScope(ND, getCurLexicalContext(), CurScope)) { Diag(Id.getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -1968,9 +2122,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] // A threadprivate directive must lexically precede all references to any // of the variables in its list. - if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) { + if (Kind == OMPD_threadprivate && VD->isUsed() && + !DSAStack->isThreadPrivate(VD)) { Diag(Id.getLoc(), diag::err_omp_var_used) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + << getOpenMPDirectiveName(Kind) << VD; return ExprError(); } @@ -2102,6 +2257,167 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { return D; } +static OMPAllocateDeclAttr::AllocatorTypeTy +getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) { + if (!Allocator) + return OMPAllocateDeclAttr::OMPDefaultMemAlloc; + if (Allocator->isTypeDependent() || Allocator->isValueDependent() || + Allocator->isInstantiationDependent() || + Allocator->containsUnexpandedParameterPack()) + return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; + auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; + const Expr *AE = Allocator->IgnoreParenImpCasts(); + for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; + I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); + const Expr *DefAllocator = Stack->getAllocator(AllocatorKind); + llvm::FoldingSetNodeID AEId, DAEId; + AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true); + DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true); + if (AEId == DAEId) { + AllocatorKindRes = AllocatorKind; + break; + } + } + return AllocatorKindRes; +} + +static bool checkPreviousOMPAllocateAttribute( + Sema &S, DSAStackTy *Stack, Expr *RefExpr, VarDecl *VD, + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) { + if (!VD->hasAttr<OMPAllocateDeclAttr>()) + return false; + const auto *A = VD->getAttr<OMPAllocateDeclAttr>(); + Expr *PrevAllocator = A->getAllocator(); + OMPAllocateDeclAttr::AllocatorTypeTy PrevAllocatorKind = + getAllocatorKind(S, Stack, PrevAllocator); + bool AllocatorsMatch = AllocatorKind == PrevAllocatorKind; + if (AllocatorsMatch && + AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc && + Allocator && PrevAllocator) { + const Expr *AE = Allocator->IgnoreParenImpCasts(); + const Expr *PAE = PrevAllocator->IgnoreParenImpCasts(); + llvm::FoldingSetNodeID AEId, PAEId; + AE->Profile(AEId, S.Context, /*Canonical=*/true); + PAE->Profile(PAEId, S.Context, /*Canonical=*/true); + AllocatorsMatch = AEId == PAEId; + } + if (!AllocatorsMatch) { + SmallString<256> AllocatorBuffer; + llvm::raw_svector_ostream AllocatorStream(AllocatorBuffer); + if (Allocator) + Allocator->printPretty(AllocatorStream, nullptr, S.getPrintingPolicy()); + SmallString<256> PrevAllocatorBuffer; + llvm::raw_svector_ostream PrevAllocatorStream(PrevAllocatorBuffer); + if (PrevAllocator) + PrevAllocator->printPretty(PrevAllocatorStream, nullptr, + S.getPrintingPolicy()); + + SourceLocation AllocatorLoc = + Allocator ? Allocator->getExprLoc() : RefExpr->getExprLoc(); + SourceRange AllocatorRange = + Allocator ? Allocator->getSourceRange() : RefExpr->getSourceRange(); + SourceLocation PrevAllocatorLoc = + PrevAllocator ? PrevAllocator->getExprLoc() : A->getLocation(); + SourceRange PrevAllocatorRange = + PrevAllocator ? PrevAllocator->getSourceRange() : A->getRange(); + S.Diag(AllocatorLoc, diag::warn_omp_used_different_allocator) + << (Allocator ? 1 : 0) << AllocatorStream.str() + << (PrevAllocator ? 1 : 0) << PrevAllocatorStream.str() + << AllocatorRange; + S.Diag(PrevAllocatorLoc, diag::note_omp_previous_allocator) + << PrevAllocatorRange; + return true; + } + return false; +} + +static void +applyOMPAllocateAttribute(Sema &S, VarDecl *VD, + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, + Expr *Allocator, SourceRange SR) { + if (VD->hasAttr<OMPAllocateDeclAttr>()) + return; + if (Allocator && + (Allocator->isTypeDependent() || Allocator->isValueDependent() || + Allocator->isInstantiationDependent() || + Allocator->containsUnexpandedParameterPack())) + return; + auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind, + Allocator, SR); + VD->addAttr(A); + if (ASTMutationListener *ML = S.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPAllocate(VD, A); +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective( + SourceLocation Loc, ArrayRef<Expr *> VarList, + ArrayRef<OMPClause *> Clauses, DeclContext *Owner) { + assert(Clauses.size() <= 1 && "Expected at most one clause."); + Expr *Allocator = nullptr; + if (Clauses.empty()) { + // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions. + // allocate directives that appear in a target region must specify an + // allocator clause unless a requires directive with the dynamic_allocators + // clause is present in the same compilation unit. + if (LangOpts.OpenMPIsDevice && + !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>()) + targetDiag(Loc, diag::err_expected_allocator_clause); + } else { + Allocator = cast<OMPAllocatorClause>(Clauses.back())->getAllocator(); + } + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = + getAllocatorKind(*this, DSAStack, Allocator); + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + auto *DE = cast<DeclRefExpr>(RefExpr); + auto *VD = cast<VarDecl>(DE->getDecl()); + + // Check if this is a TLS variable or global register. + if (VD->getTLSKind() != VarDecl::TLS_None || + VD->hasAttr<OMPThreadPrivateDeclAttr>() || + (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && + !VD->isLocalVarDecl())) + continue; + + // If the used several times in the allocate directive, the same allocator + // must be used. + if (checkPreviousOMPAllocateAttribute(*this, DSAStack, RefExpr, VD, + AllocatorKind, Allocator)) + continue; + + // OpenMP, 2.11.3 allocate Directive, Restrictions, C / C++ + // If a list item has a static storage type, the allocator expression in the + // allocator clause must be a constant expression that evaluates to one of + // the predefined memory allocator values. + if (Allocator && VD->hasGlobalStorage()) { + if (AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc) { + Diag(Allocator->getExprLoc(), + diag::err_omp_expected_predefined_allocator) + << Allocator->getSourceRange(); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + } + + Vars.push_back(RefExpr); + applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, + DE->getSourceRange()); + } + if (Vars.empty()) + return nullptr; + if (!Owner) + Owner = getCurLexicalContext(); + auto *D = OMPAllocateDecl::Create(Context, Owner, Loc, Vars, Clauses); + D->setAccess(AS_public); + Owner->addDecl(D); + return DeclGroupPtrTy::make(DeclGroupRef(D)); +} + Sema::DeclGroupPtrTy Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc, ArrayRef<OMPClause *> ClauseList) { @@ -2120,6 +2436,27 @@ Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc, OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc, ArrayRef<OMPClause *> ClauseList) { + /// For target specific clauses, the requires directive cannot be + /// specified after the handling of any of the target regions in the + /// current compilation unit. + ArrayRef<SourceLocation> TargetLocations = + DSAStack->getEncounteredTargetLocs(); + if (!TargetLocations.empty()) { + for (const OMPClause *CNew : ClauseList) { + // Check if any of the requires clauses affect target regions. + if (isa<OMPUnifiedSharedMemoryClause>(CNew) || + isa<OMPUnifiedAddressClause>(CNew) || + isa<OMPReverseOffloadClause>(CNew) || + isa<OMPDynamicAllocatorsClause>(CNew)) { + Diag(Loc, diag::err_omp_target_before_requires) + << getOpenMPClauseName(CNew->getClauseKind()); + for (SourceLocation TargetLoc : TargetLocations) { + Diag(TargetLoc, diag::note_omp_requires_encountered_target); + } + } + } + } + if (!DSAStack->hasDuplicateRequiresClause(ClauseList)) return OMPRequiresDecl::Create(Context, getCurLexicalContext(), Loc, ClauseList); @@ -2224,9 +2561,17 @@ public: E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) return; if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { + // Check the datasharing rules for the expressions in the clauses. + if (!CS) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD)) + if (!CED->hasAttr<OMPCaptureNoInitAttr>()) { + Visit(CED->getInit()); + return; + } + } VD = VD->getCanonicalDecl(); // Skip internally declared variables. - if (VD->hasLocalStorage() && !CS->capturesVariable(VD)) + if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD)) return; DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false); @@ -2237,7 +2582,7 @@ public: // Skip internally declared static variables. llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); - if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) && + if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) && (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)) return; @@ -2315,8 +2660,18 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false); if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && - !Stack->isLoopControlVariable(VD).first) + !Stack->isLoopControlVariable(VD).first) { ImplicitFirstprivate.push_back(E); + return; + } + + // Store implicitly used globals with declare target link for parent + // target. + if (!isOpenMPTargetExecutionDirective(DKind) && Res && + *Res == OMPDeclareTargetDeclAttr::MT_Link) { + Stack->addToParentTargetRegionLinkGlobals(E); + return; + } } } void VisitMemberExpr(MemberExpr *E) { @@ -2474,7 +2829,13 @@ public: } DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS) - : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {} + : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) { + // Process declare target link variables for the target directives. + if (isOpenMPTargetExecutionDirective(S->getCurrentDirective())) { + for (DeclRefExpr *E : Stack->getLinkGlobals()) + Visit(E); + } + } }; } // namespace @@ -2802,6 +3163,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: @@ -2809,6 +3171,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancel: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -3346,6 +3709,169 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, return ErrorFound; } +static std::pair<ValueDecl *, bool> +getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, + SourceRange &ERange, bool AllowArraySection = false) { + if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || + RefExpr->containsUnexpandedParameterPack()) + return std::make_pair(nullptr, true); + + // OpenMP [3.1, C/C++] + // A list item is a variable name. + // OpenMP [2.9.3.3, Restrictions, p.1] + // A variable that is part of another variable (as an array or + // structure element) cannot appear in a private clause. + RefExpr = RefExpr->IgnoreParens(); + enum { + NoArrayExpr = -1, + ArraySubscript = 0, + OMPArraySection = 1 + } IsArrayExpr = NoArrayExpr; + if (AllowArraySection) { + if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) { + Expr *Base = ASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = ArraySubscript; + } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) { + Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = OMPArraySection; + } + } + ELoc = RefExpr->getExprLoc(); + ERange = RefExpr->getSourceRange(); + RefExpr = RefExpr->IgnoreParenImpCasts(); + auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); + auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr); + if ((!DE || !isa<VarDecl>(DE->getDecl())) && + (S.getCurrentThisType().isNull() || !ME || + !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) || + !isa<FieldDecl>(ME->getMemberDecl()))) { + if (IsArrayExpr != NoArrayExpr) { + S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr + << ERange; + } else { + S.Diag(ELoc, + AllowArraySection + ? diag::err_omp_expected_var_name_member_expr_or_array_item + : diag::err_omp_expected_var_name_member_expr) + << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange; + } + return std::make_pair(nullptr, false); + } + return std::make_pair( + getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); +} + +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses) { + assert(!S.CurContext->isDependentContext() && + "Expected non-dependent context."); + auto AllocateRange = + llvm::make_filter_range(Clauses, OMPAllocateClause::classof); + llvm::DenseMap<CanonicalDeclPtr<Decl>, CanonicalDeclPtr<VarDecl>> + DeclToCopy; + auto PrivateRange = llvm::make_filter_range(Clauses, [](const OMPClause *C) { + return isOpenMPPrivate(C->getClauseKind()); + }); + for (OMPClause *Cl : PrivateRange) { + MutableArrayRef<Expr *>::iterator I, It, Et; + if (Cl->getClauseKind() == OMPC_private) { + auto *PC = cast<OMPPrivateClause>(Cl); + I = PC->private_copies().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_firstprivate) { + auto *PC = cast<OMPFirstprivateClause>(Cl); + I = PC->private_copies().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_lastprivate) { + auto *PC = cast<OMPLastprivateClause>(Cl); + I = PC->private_copies().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_linear) { + auto *PC = cast<OMPLinearClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_reduction) { + auto *PC = cast<OMPReductionClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_task_reduction) { + auto *PC = cast<OMPTaskReductionClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else if (Cl->getClauseKind() == OMPC_in_reduction) { + auto *PC = cast<OMPInReductionClause>(Cl); + I = PC->privates().begin(); + It = PC->varlist_begin(); + Et = PC->varlist_end(); + } else { + llvm_unreachable("Expected private clause."); + } + for (Expr *E : llvm::make_range(It, Et)) { + if (!*I) { + ++I; + continue; + } + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = E; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + DeclToCopy.try_emplace(Res.first, + cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl())); + ++I; + } + } + for (OMPClause *C : AllocateRange) { + auto *AC = cast<OMPAllocateClause>(C); + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = + getAllocatorKind(S, Stack, AC->getAllocator()); + // OpenMP, 2.11.4 allocate Clause, Restrictions. + // For task, taskloop or target directives, allocation requests to memory + // allocators with the trait access set to thread result in unspecified + // behavior. + if (AllocatorKind == OMPAllocateDeclAttr::OMPThreadMemAlloc && + (isOpenMPTaskingDirective(Stack->getCurrentDirective()) || + isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()))) { + S.Diag(AC->getAllocator()->getExprLoc(), + diag::warn_omp_allocate_thread_on_task_target_directive) + << getOpenMPDirectiveName(Stack->getCurrentDirective()); + } + for (Expr *E : AC->varlists()) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = E; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange); + ValueDecl *VD = Res.first; + DSAStackTy::DSAVarData Data = Stack->getTopDSA(VD, /*FromParent=*/false); + if (!isOpenMPPrivate(Data.CKind)) { + S.Diag(E->getExprLoc(), + diag::err_omp_expected_private_copy_for_allocate); + continue; + } + VarDecl *PrivateVD = DeclToCopy[VD]; + if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD, + AllocatorKind, AC->getAllocator())) + continue; + applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(), + E->getSourceRange()); + } + } +} + StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, @@ -3401,11 +3927,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( } } if (!ImplicitMaps.empty()) { + CXXScopeSpec MapperIdScopeSpec; + DeclarationNameInfo MapperId; if (OMPClause *Implicit = ActOnOpenMPMapClause( - llvm::None, llvm::None, OMPC_MAP_tofrom, - /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), - ImplicitMaps, SourceLocation(), SourceLocation(), - SourceLocation())) { + llvm::None, llvm::None, MapperIdScopeSpec, MapperId, + OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(), + SourceLocation(), ImplicitMaps, OMPVarListLocTy())) { ClausesWithImplicit.emplace_back(Implicit); ErrorFound |= cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size(); @@ -3656,7 +4183,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_requires: llvm_unreachable("OpenMP Directive is not allowed"); @@ -3664,9 +4193,96 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( llvm_unreachable("Unknown OpenMP directive"); } + ErrorFound = Res.isInvalid() || ErrorFound; + + // Check variables in the clauses if default(none) was specified. + if (DSAStack->getDefaultDSA() == DSA_none) { + DSAAttrChecker DSAChecker(DSAStack, *this, nullptr); + for (OMPClause *C : Clauses) { + switch (C->getClauseKind()) { + case OMPC_num_threads: + case OMPC_dist_schedule: + // Do not analyse if no parent teams directive. + if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective())) + break; + continue; + case OMPC_if: + if ((isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) && + cast<OMPIfClause>(C)->getNameModifier() != OMPD_target) || + isOpenMPParallelDirective(DSAStack->getCurrentDirective())) + break; + continue; + case OMPC_schedule: + break; + case OMPC_ordered: + case OMPC_device: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_num_tasks: + case OMPC_hint: + case OMPC_collapse: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_final: + case OMPC_default: + case OMPC_proc_bind: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_shared: + case OMPC_reduction: + case OMPC_task_reduction: + case OMPC_in_reduction: + case OMPC_linear: + case OMPC_aligned: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + case OMPC_allocate: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: + case OMPC_depend: + case OMPC_threads: + case OMPC_simd: + case OMPC_map: + case OMPC_nogroup: + case OMPC_defaultmap: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: + continue; + case OMPC_allocator: + case OMPC_flush: + case OMPC_threadprivate: + case OMPC_uniform: + case OMPC_unknown: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: + case OMPC_atomic_default_mem_order: + llvm_unreachable("Unexpected clause"); + } + for (Stmt *CC : C->children()) { + if (CC) + DSAChecker.Visit(CC); + } + } + for (auto &P : DSAChecker.getVarsWithInheritedDSA()) + VarsWithInheritedDSA[P.getFirst()] = P.getSecond(); + } for (const auto &P : VarsWithInheritedDSA) { Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); + Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none); } ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound; @@ -3676,6 +4292,23 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (ErrorFound) return StmtError(); + + if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) { + Res.getAs<OMPExecutableDirective>() + ->getStructuredBlock() + ->setIsOMPStructuredBlock(true); + } + + if (!CurContext->isDependentContext() && + isOpenMPTargetExecutionDirective(Kind) && + !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || + DSAStack->hasRequiresDeclWithClause<OMPUnifiedAddressClause>() || + DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>() || + DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())) { + // Register target to DSA Stack. + DSAStack->addTargetDirLocation(StartLoc); + } + return Res; } @@ -3953,6 +4586,8 @@ namespace { class OpenMPIterationSpaceChecker { /// Reference to Sema. Sema &SemaRef; + /// Data-sharing stack. + DSAStackTy &Stack; /// A location for diagnostics (when there is no some better location). SourceLocation DefaultLoc; /// A location for diagnostics (when increment is not compatible). @@ -3984,10 +4619,22 @@ class OpenMPIterationSpaceChecker { bool TestIsStrictOp = false; /// This flag is true when step is subtracted on each iteration. bool SubtractStep = false; + /// The outer loop counter this loop depends on (if any). + const ValueDecl *DepDecl = nullptr; + /// Contains number of loop (starts from 1) on which loop counter init + /// expression of this loop depends on. + Optional<unsigned> InitDependOnLC; + /// Contains number of loop (starts from 1) on which loop counter condition + /// expression of this loop depends on. + Optional<unsigned> CondDependOnLC; + /// Checks if the provide statement depends on the loop counter. + Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); public: - OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) - : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} + OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, + SourceLocation DefaultLoc) + : SemaRef(SemaRef), Stack(Stack), DefaultLoc(DefaultLoc), + ConditionLoc(DefaultLoc) {} /// Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool checkAndSetInit(Stmt *S, bool EmitDiags = true); @@ -4009,6 +4656,8 @@ public: SourceRange getIncrementSrcRange() const { return IncrementSrcRange; } /// True if the step should be subtracted. bool shouldSubtractStep() const { return SubtractStep; } + /// True, if the compare operator is strict (<, > or !=). + bool isStrictTestOp() const { return TestIsStrictOp; } /// Build the expression to calculate the number of iterations. Expr *buildNumIterations( Scope *S, const bool LimitedType, @@ -4043,7 +4692,8 @@ private: /// expression. bool checkAndSetIncRHS(Expr *RHS); /// Helper to set loop counter variable and its initializer. - bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); + bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB, + bool EmitDiags); /// Helper to set upper bound. bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); @@ -4063,7 +4713,7 @@ bool OpenMPIterationSpaceChecker::dependent() const { bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewLCRefExpr, - Expr *NewLB) { + Expr *NewLB, bool EmitDiags) { // State consistency checking to ensure correct usage. assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); @@ -4078,10 +4728,13 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) NewLB = CE->getArg(0)->IgnoreParenImpCasts(); LB = NewLB; + if (EmitDiags) + InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true); return false; } -bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp, +bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, + llvm::Optional<bool> LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. @@ -4095,6 +4748,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp TestIsStrictOp = StrictOp; ConditionSrcRange = SR; ConditionLoc = SL; + CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false); return false; } @@ -4160,6 +4814,109 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { return false; } +namespace { +/// Checker for the non-rectangular loops. Checks if the initializer or +/// condition expression references loop counter variable. +class LoopCounterRefChecker final + : public ConstStmtVisitor<LoopCounterRefChecker, bool> { + Sema &SemaRef; + DSAStackTy &Stack; + const ValueDecl *CurLCDecl = nullptr; + const ValueDecl *DepDecl = nullptr; + const ValueDecl *PrevDepDecl = nullptr; + bool IsInitializer = true; + unsigned BaseLoopId = 0; + bool checkDecl(const Expr *E, const ValueDecl *VD) { + if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) { + SemaRef.Diag(E->getExprLoc(), diag::err_omp_stmt_depends_on_loop_counter) + << (IsInitializer ? 0 : 1); + return false; + } + const auto &&Data = Stack.isLoopControlVariable(VD); + // OpenMP, 2.9.1 Canonical Loop Form, Restrictions. + // The type of the loop iterator on which we depend may not have a random + // access iterator type. + if (Data.first && VD->getType()->isRecordType()) { + SmallString<128> Name; + llvm::raw_svector_ostream OS(Name); + VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), + /*Qualified=*/true); + SemaRef.Diag(E->getExprLoc(), + diag::err_omp_wrong_dependency_iterator_type) + << OS.str(); + SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD; + return false; + } + if (Data.first && + (DepDecl || (PrevDepDecl && + getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) { + if (!DepDecl && PrevDepDecl) + DepDecl = PrevDepDecl; + SmallString<128> Name; + llvm::raw_svector_ostream OS(Name); + DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), + /*Qualified=*/true); + SemaRef.Diag(E->getExprLoc(), + diag::err_omp_invariant_or_linear_dependency) + << OS.str(); + return false; + } + if (Data.first) { + DepDecl = VD; + BaseLoopId = Data.first; + } + return Data.first; + } + +public: + bool VisitDeclRefExpr(const DeclRefExpr *E) { + const ValueDecl *VD = E->getDecl(); + if (isa<VarDecl>(VD)) + return checkDecl(E, VD); + return false; + } + bool VisitMemberExpr(const MemberExpr *E) { + if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) { + const ValueDecl *VD = E->getMemberDecl(); + return checkDecl(E, VD); + } + return false; + } + bool VisitStmt(const Stmt *S) { + bool Res = true; + for (const Stmt *Child : S->children()) + Res = Child && Visit(Child) && Res; + return Res; + } + explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, + const ValueDecl *CurLCDecl, bool IsInitializer, + const ValueDecl *PrevDepDecl = nullptr) + : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl), + PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer) {} + unsigned getBaseLoopId() const { + assert(CurLCDecl && "Expected loop dependency."); + return BaseLoopId; + } + const ValueDecl *getDepDecl() const { + assert(CurLCDecl && "Expected loop dependency."); + return DepDecl; + } +}; +} // namespace + +Optional<unsigned> +OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, + bool IsInitializer) { + // Check for the non-rectangular loops. + LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer, + DepDecl); + if (LoopStmtChecker.Visit(S)) { + DepDecl = LoopStmtChecker.getDepDecl(); + return LoopStmtChecker.getBaseLoopId(); + } + return llvm::None; +} + bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { // Check init-expr for canonical loop form and save loop counter // variable - #Var and its initialization value - #LB. @@ -4188,13 +4945,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); - return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); + return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); } } } else if (auto *DS = dyn_cast<DeclStmt>(S)) { @@ -4211,7 +4970,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(), DS->getBeginLoc()), - Var->getInit()); + Var->getInit(), EmitDiags); } } } @@ -4221,13 +4980,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); - return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); + return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) - return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(), + EmitDiags); } } } @@ -4581,7 +5342,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond( /*AllowExplicit=*/true); } SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); - // Otherwise use original loop conditon and evaluate it in runtime. + // Otherwise use original loop condition and evaluate it in runtime. return CondExpr.isUsable() ? CondExpr.get() : Cond; } @@ -4602,8 +5363,7 @@ DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar( Captures.insert(std::make_pair(LCRef, Ref)); return Ref; } - return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(), - DefaultLoc); + return cast<DeclRefExpr>(LCRef); } Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const { @@ -4648,10 +5408,12 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower - Expr *Upper = - TestIsLessOp.getValue() ? Cnt : tryBuildCapture(SemaRef, UB, Captures).get(); - Expr *Lower = - TestIsLessOp.getValue() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt; + Expr *Upper = TestIsLessOp.getValue() + ? Cnt + : tryBuildCapture(SemaRef, UB, Captures).get(); + Expr *Lower = TestIsLessOp.getValue() + ? tryBuildCapture(SemaRef, LB, Captures).get() + : Cnt; if (!Upper || !Lower) return nullptr; @@ -4687,6 +5449,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( /// Iteration space of a single for loop. struct LoopIterationSpace final { + /// True if the condition operator is the strict compare operator (<, > or + /// !=). + bool IsStrictCompare = false; /// Condition of the loop. Expr *PreCond = nullptr; /// This expression calculates the number of iterations in the loop. @@ -4720,7 +5485,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { DSAStack->loopStart(); - OpenMPIterationSpaceChecker ISC(*this, ForLoc); + OpenMPIterationSpaceChecker ISC(*this, *DSAStack, ForLoc); if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast<VarDecl>(D); @@ -4786,7 +5551,7 @@ static bool checkOpenMPIterationSpace( } assert(For->getBody()); - OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc()); + OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc()); // Check init. Stmt *Init = For->getInit(); @@ -4859,10 +5624,7 @@ static bool checkOpenMPIterationSpace( // lastprivate (for simd directives with several collapsed or ordered // loops). if (DVar.CKind == OMPC_unknown) - DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate, - [](OpenMPDirectiveKind) -> bool { return true; }, - /*FromParent=*/false); - DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); + DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); } assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); @@ -4893,6 +5655,7 @@ static bool checkOpenMPIterationSpace( ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange(); ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange(); ResultIterSpace.Subtract = ISC.shouldSubtractStep(); + ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp(); HasErrors |= (ResultIterSpace.PreCond == nullptr || ResultIterSpace.NumIterations == nullptr || @@ -5140,8 +5903,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). llvm::MapVector<const Expr *, DeclRefExpr *> Captures; - SmallVector<LoopIterationSpace, 4> IterSpaces; - IterSpaces.resize(std::max(OrderedLoopCount, NestedLoopCount)); + SmallVector<LoopIterationSpace, 4> IterSpaces( + std::max(OrderedLoopCount, NestedLoopCount)); Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { if (checkOpenMPIterationSpace( @@ -5447,25 +6210,55 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } } - // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. + bool UseStrictCompare = + RealVType->hasUnsignedIntegerRepresentation() && + llvm::all_of(IterSpaces, [](const LoopIterationSpace &LIS) { + return LIS.IsStrictCompare; + }); + // Loop condition (IV < NumIterations) or (IV <= UB or IV < UB + 1 (for + // unsigned IV)) for worksharing loops. SourceLocation CondLoc = AStmt->getBeginLoc(); + Expr *BoundUB = UB.get(); + if (UseStrictCompare) { + BoundUB = + SemaRef + .BuildBinOp(CurScope, CondLoc, BO_Add, BoundUB, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) + .get(); + BoundUB = + SemaRef.ActOnFinishFullExpr(BoundUB, /*DiscardedValue*/ false).get(); + } ExprResult Cond = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) - ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) + ? SemaRef.BuildBinOp(CurScope, CondLoc, + UseStrictCompare ? BO_LT : BO_LE, IV.get(), + BoundUB) : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); ExprResult CombDistCond; if (isOpenMPLoopBoundSharingDirective(DKind)) { - CombDistCond = - SemaRef.BuildBinOp( - CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get()); + CombDistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), + NumIterations.get()); } ExprResult CombCond; if (isOpenMPLoopBoundSharingDirective(DKind)) { + Expr *BoundCombUB = CombUB.get(); + if (UseStrictCompare) { + BoundCombUB = + SemaRef + .BuildBinOp( + CurScope, CondLoc, BO_Add, BoundCombUB, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) + .get(); + BoundCombUB = + SemaRef.ActOnFinishFullExpr(BoundCombUB, /*DiscardedValue*/ false) + .get(); + } CombCond = - SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get()); + SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, + IV.get(), BoundCombUB); } // Loop increment (IV = IV + 1) SourceLocation IncLoc = AStmt->getBeginLoc(); @@ -5542,7 +6335,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation DistIncLoc = AStmt->getBeginLoc(); ExprResult DistCond, DistInc, PrevEUB, ParForInDistCond; if (isOpenMPLoopBoundSharingDirective(DKind)) { - DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()); + DistCond = SemaRef.BuildBinOp( + CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, IV.get(), BoundUB); assert(DistCond.isUsable() && "distribute cond expr was not built"); DistInc = @@ -5566,10 +6360,24 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, PrevEUB = SemaRef.ActOnFinishFullExpr(PrevEUB.get(), /*DiscardedValue*/ false); - // Build IV <= PrevUB to be used in parallel for is in combination with - // a distribute directive with schedule(static, 1) + // Build IV <= PrevUB or IV < PrevUB + 1 for unsigned IV to be used in + // parallel for is in combination with a distribute directive with + // schedule(static, 1) + Expr *BoundPrevUB = PrevUB.get(); + if (UseStrictCompare) { + BoundPrevUB = + SemaRef + .BuildBinOp( + CurScope, CondLoc, BO_Add, BoundPrevUB, + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) + .get(); + BoundPrevUB = + SemaRef.ActOnFinishFullExpr(BoundPrevUB, /*DiscardedValue*/ false) + .get(); + } ParForInDistCond = - SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), PrevUB.get()); + SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, + IV.get(), BoundPrevUB); } // Build updates and final values of the loop counters. @@ -7015,7 +7823,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, auto I = CS->body_begin(); while (I != CS->body_end()) { const auto *OED = dyn_cast<OMPExecutableDirective>(*I); - if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) { + if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind()) || + OMPTeamsFound) { + OMPTeamsFound = false; break; } @@ -8235,6 +9045,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_simdlen: Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_allocator: + Res = ActOnOpenMPAllocatorClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_collapse: Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -8281,6 +9094,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -8365,12 +9179,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( // Do not capture if-clause expressions. break; case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8431,12 +9247,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskloop: case OMPD_taskloop_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8498,12 +9316,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8562,12 +9382,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8627,12 +9449,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel: case OMPD_parallel_sections: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8691,12 +9515,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel: case OMPD_parallel_sections: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8754,12 +9580,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_threadprivate: + case OMPD_allocate: case OMPD_taskyield: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: case OMPD_declare_reduction: + case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: @@ -8793,6 +9621,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_final: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_private: case OMPC_shared: @@ -8804,6 +9633,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -9042,6 +9872,71 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc, OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc); } +/// Tries to find omp_allocator_handle_t type. +static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, + DSAStackTy *Stack) { + QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT(); + if (!OMPAllocatorHandleT.isNull()) + return true; + // Build the predefined allocator expressions. + bool ErrorFound = false; + for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; + I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); + StringRef Allocator = + OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind); + DeclarationName AllocatorName = &S.getASTContext().Idents.get(Allocator); + auto *VD = dyn_cast_or_null<ValueDecl>( + S.LookupSingleName(S.TUScope, AllocatorName, Loc, Sema::LookupAnyName)); + if (!VD) { + ErrorFound = true; + break; + } + QualType AllocatorType = + VD->getType().getNonLValueExprType(S.getASTContext()); + ExprResult Res = S.BuildDeclRefExpr(VD, AllocatorType, VK_LValue, Loc); + if (!Res.isUsable()) { + ErrorFound = true; + break; + } + if (OMPAllocatorHandleT.isNull()) + OMPAllocatorHandleT = AllocatorType; + if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) { + ErrorFound = true; + break; + } + Stack->setAllocator(AllocatorKind, Res.get()); + } + if (ErrorFound) { + S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found); + return false; + } + OMPAllocatorHandleT.addConst(); + Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT); + return true; +} + +OMPClause *Sema::ActOnOpenMPAllocatorClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + // OpenMP [2.11.3, allocate Directive, Description] + // allocator is an expression of omp_allocator_handle_t type. + if (!findOMPAllocatorHandleT(*this, A->getExprLoc(), DSAStack)) + return nullptr; + + ExprResult Allocator = DefaultLvalueConversion(A); + if (Allocator.isInvalid()) + return nullptr; + Allocator = PerformImplicitConversion(Allocator.get(), + DSAStack->getOMPAllocatorHandleT(), + Sema::AA_Initializing, + /*AllowExplicit=*/true); + if (Allocator.isInvalid()) + return nullptr; + return new (Context) + OMPAllocatorClause(Allocator.get(), StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9109,6 +10004,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_schedule: case OMPC_private: @@ -9127,6 +10023,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -9285,6 +10182,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: @@ -9304,6 +10202,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_read: case OMPC_write: @@ -9505,6 +10404,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_schedule: case OMPC_private: @@ -9521,6 +10421,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_default: case OMPC_proc_bind: case OMPC_threadprivate: + case OMPC_allocate: case OMPC_flush: case OMPC_depend: case OMPC_device: @@ -9623,14 +10524,16 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, - SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, - SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, + const OMPVarListLocTy &Locs, SourceLocation ColonLoc, + CXXScopeSpec &ReductionOrMapperIdScopeSpec, + DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind, OpenMPLinearClauseKind LinKind, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, - ArrayRef<SourceLocation> MapTypeModifiersLoc, - OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, - SourceLocation DepLinMapLoc) { + ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType, + bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) { + SourceLocation StartLoc = Locs.StartLoc; + SourceLocation LParenLoc = Locs.LParenLoc; + SourceLocation EndLoc = Locs.EndLoc; OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: @@ -9647,17 +10550,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( break; case OMPC_reduction: Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, ReductionId); + EndLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId); break; case OMPC_task_reduction: Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, - ReductionId); + EndLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId); break; case OMPC_in_reduction: - Res = - ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, ReductionId); + Res = ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, + EndLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId); break; case OMPC_linear: Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, @@ -9681,27 +10585,35 @@ OMPClause *Sema::ActOnOpenMPVarListClause( StartLoc, LParenLoc, EndLoc); break; case OMPC_map: - Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, MapType, - IsMapTypeImplicit, DepLinMapLoc, ColonLoc, - VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, + ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, MapType, IsMapTypeImplicit, + DepLinMapLoc, ColonLoc, VarList, Locs); break; case OMPC_to: - Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, Locs); break; case OMPC_from: - Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPFromClause(VarList, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, Locs); break; case OMPC_use_device_ptr: - Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs); break; case OMPC_is_device_ptr: - Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); + break; + case OMPC_allocate: + Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, + ColonLoc, EndLoc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: case OMPC_collapse: case OMPC_default: case OMPC_proc_bind: @@ -9759,66 +10671,6 @@ ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, return Res; } -static std::pair<ValueDecl *, bool> -getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, - SourceRange &ERange, bool AllowArraySection = false) { - if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || - RefExpr->containsUnexpandedParameterPack()) - return std::make_pair(nullptr, true); - - // OpenMP [3.1, C/C++] - // A list item is a variable name. - // OpenMP [2.9.3.3, Restrictions, p.1] - // A variable that is part of another variable (as an array or - // structure element) cannot appear in a private clause. - RefExpr = RefExpr->IgnoreParens(); - enum { - NoArrayExpr = -1, - ArraySubscript = 0, - OMPArraySection = 1 - } IsArrayExpr = NoArrayExpr; - if (AllowArraySection) { - if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) { - Expr *Base = ASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) - Base = TempASE->getBase()->IgnoreParenImpCasts(); - RefExpr = Base; - IsArrayExpr = ArraySubscript; - } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) { - Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) - Base = TempOASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) - Base = TempASE->getBase()->IgnoreParenImpCasts(); - RefExpr = Base; - IsArrayExpr = OMPArraySection; - } - } - ELoc = RefExpr->getExprLoc(); - ERange = RefExpr->getSourceRange(); - RefExpr = RefExpr->IgnoreParenImpCasts(); - auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr); - if ((!DE || !isa<VarDecl>(DE->getDecl())) && - (S.getCurrentThisType().isNull() || !ME || - !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) || - !isa<FieldDecl>(ME->getMemberDecl()))) { - if (IsArrayExpr != NoArrayExpr) { - S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr - << ERange; - } else { - S.Diag(ELoc, - AllowArraySection - ? diag::err_omp_expected_var_name_member_expr_or_array_item - : diag::err_omp_expected_var_name_member_expr) - << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange; - } - return std::make_pair(nullptr, false); - } - return std::make_pair( - getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); -} - OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -10511,8 +11363,8 @@ public: } // namespace template <typename T, typename U> -static T filterLookupForUDR(SmallVectorImpl<U> &Lookups, - const llvm::function_ref<T(ValueDecl *)> Gen) { +static T filterLookupForUDReductionAndMapper( + SmallVectorImpl<U> &Lookups, const llvm::function_ref<T(ValueDecl *)> Gen) { for (U &Set : Lookups) { for (auto *D : Set) { if (T Res = Gen(cast<ValueDecl>(D))) @@ -10539,7 +11391,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { } static void -argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId, +argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &Id, SourceLocation Loc, QualType Ty, SmallVectorImpl<UnresolvedSet<8>> &Lookups) { // Find all of the associated namespaces and classes based on the @@ -10573,13 +11425,14 @@ argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId, // associated classes are visible within their respective // namespaces even if they are not visible during an ordinary // lookup (11.4). - DeclContext::lookup_result R = NS->lookup(ReductionId.getName()); + DeclContext::lookup_result R = NS->lookup(Id.getName()); for (auto *D : R) { auto *Underlying = D; if (auto *USD = dyn_cast<UsingShadowDecl>(D)) Underlying = USD->getTargetDecl(); - if (!isa<OMPDeclareReductionDecl>(Underlying)) + if (!isa<OMPDeclareReductionDecl>(Underlying) && + !isa<OMPDeclareMapperDecl>(Underlying)) continue; if (!SemaRef.isVisible(D)) { @@ -10624,7 +11477,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, for (NamedDecl *D : ULE->decls()) { if (D == PrevD) Lookups.push_back(UnresolvedSet<8>()); - else if (auto *DRD = cast<OMPDeclareReductionDecl>(D)) + else if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(D)) Lookups.back().addDecl(DRD); PrevD = D; } @@ -10632,7 +11485,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() || Ty->isInstantiationDependentType() || Ty->containsUnexpandedParameterPack() || - filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) { + filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) { return !D->isInvalidDecl() && (D->getType()->isDependentType() || D->getType()->isInstantiationDependentType() || @@ -10680,33 +11533,38 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, } } // Perform ADL. - argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups); - if (auto *VD = filterLookupForUDR<ValueDecl *>( + if (SemaRef.getLangOpts().CPlusPlus) + argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups); + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * { if (!D->isInvalidDecl() && SemaRef.Context.hasSameType(D->getType(), Ty)) return D; return nullptr; })) - return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); - if (auto *VD = filterLookupForUDR<ValueDecl *>( - Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { - if (!D->isInvalidDecl() && - SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && - !Ty.isMoreQualifiedThan(D->getType())) - return D; - return nullptr; - })) { - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) { - if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( - VD->getType().getUnqualifiedType()))) { - if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(), - /*DiagID=*/0) != - Sema::AR_inaccessible) { - SemaRef.BuildBasePathArray(Paths, BasePath); - return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); + return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), + VK_LValue, Loc); + if (SemaRef.getLangOpts().CPlusPlus) { + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( + Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && + !Ty.isMoreQualifiedThan(D->getType())) + return D; + return nullptr; + })) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) { + if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( + VD->getType().getUnqualifiedType()))) { + if (SemaRef.CheckBaseClassAccess( + Loc, VD->getType(), Ty, Paths.front(), + /*DiagID=*/0) != Sema::AR_inaccessible) { + SemaRef.BuildBasePathArray(Paths, BasePath); + return SemaRef.BuildDeclRefExpr( + VD, VD->getType().getNonReferenceType(), VK_LValue, Loc); + } } } } @@ -11300,7 +12158,8 @@ static bool actOnOMPReductionKindClause( S.ActOnUninitializedDecl(RHSVD); if (RHSVD->isInvalidDecl()) continue; - if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) { + if (!RHSVD->hasInit() && + (DeclareReductionRef.isUnset() || !S.LangOpts.CPlusPlus)) { S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == @@ -12885,6 +13744,110 @@ static bool checkMapConflicts( return FoundError; } +// Look up the user-defined mapper given the mapper name and mapped type, and +// build a reference to it. +static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, + CXXScopeSpec &MapperIdScopeSpec, + const DeclarationNameInfo &MapperId, + QualType Type, + Expr *UnresolvedMapper) { + if (MapperIdScopeSpec.isInvalid()) + return ExprError(); + // Find all user-defined mappers with the given MapperId. + SmallVector<UnresolvedSet<8>, 4> Lookups; + LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName); + Lookup.suppressDiagnostics(); + if (S) { + while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) { + NamedDecl *D = Lookup.getRepresentativeDecl(); + while (S && !S->isDeclScope(D)) + S = S->getParent(); + if (S) + S = S->getParent(); + Lookups.emplace_back(); + Lookups.back().append(Lookup.begin(), Lookup.end()); + Lookup.clear(); + } + } else if (auto *ULE = cast_or_null<UnresolvedLookupExpr>(UnresolvedMapper)) { + // Extract the user-defined mappers with the given MapperId. + Lookups.push_back(UnresolvedSet<8>()); + for (NamedDecl *D : ULE->decls()) { + auto *DMD = cast<OMPDeclareMapperDecl>(D); + assert(DMD && "Expect valid OMPDeclareMapperDecl during instantiation."); + Lookups.back().addDecl(DMD); + } + } + // Defer the lookup for dependent types. The results will be passed through + // UnresolvedMapper on instantiation. + if (SemaRef.CurContext->isDependentContext() || Type->isDependentType() || + Type->isInstantiationDependentType() || + Type->containsUnexpandedParameterPack() || + filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) { + return !D->isInvalidDecl() && + (D->getType()->isDependentType() || + D->getType()->isInstantiationDependentType() || + D->getType()->containsUnexpandedParameterPack()); + })) { + UnresolvedSet<8> URS; + for (const UnresolvedSet<8> &Set : Lookups) { + if (Set.empty()) + continue; + URS.append(Set.begin(), Set.end()); + } + return UnresolvedLookupExpr::Create( + SemaRef.Context, /*NamingClass=*/nullptr, + MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId, + /*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end()); + } + // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions + // The type must be of struct, union or class type in C and C++ + if (!Type->isStructureOrClassType() && !Type->isUnionType()) + return ExprEmpty(); + SourceLocation Loc = MapperId.getLoc(); + // Perform argument dependent lookup. + if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet()) + argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups); + // Return the first user-defined mapper with the desired type. + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( + Lookups, [&SemaRef, Type](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.Context.hasSameType(D->getType(), Type)) + return D; + return nullptr; + })) + return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc); + // Find the first user-defined mapper with a type derived from the desired + // type. + if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>( + Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.IsDerivedFrom(Loc, Type, D->getType()) && + !Type.isMoreQualifiedThan(D->getType())) + return D; + return nullptr; + })) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(Loc, Type, VD->getType(), Paths)) { + if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( + VD->getType().getUnqualifiedType()))) { + if (SemaRef.CheckBaseClassAccess( + Loc, VD->getType(), Type, Paths.front(), + /*DiagID=*/0) != Sema::AR_inaccessible) { + return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc); + } + } + } + } + // Report error if a mapper is specified, but cannot be found. + if (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default") { + SemaRef.Diag(Loc, diag::err_omp_invalid_mapper) + << Type << MapperId.getName(); + return ExprError(); + } + return ExprEmpty(); +} + namespace { // Utility struct that gathers all the related lists associated with a mappable // expression. @@ -12897,6 +13860,8 @@ struct MappableVarListInfo { OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents; // The base declaration of the variable. SmallVector<ValueDecl *, 16> VarBaseDeclarations; + // The reference to the user-defined mapper associated with every expression. + SmallVector<Expr *, 16> UDMapperList; MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) { // We have a list of components and base declarations for each entry in the @@ -12908,20 +13873,37 @@ struct MappableVarListInfo { } // Check the validity of the provided variable list for the provided clause kind -// \a CKind. In the check process the valid expressions, and mappable expression -// components and variables are extracted and used to fill \a Vars, -// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and -// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'. -static void -checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, - OpenMPClauseKind CKind, MappableVarListInfo &MVLI, - SourceLocation StartLoc, - OpenMPMapClauseKind MapType = OMPC_MAP_unknown, - bool IsMapTypeImplicit = false) { +// \a CKind. In the check process the valid expressions, mappable expression +// components, variables, and user-defined mappers are extracted and used to +// fill \a ProcessedVarList, \a VarComponents, \a VarBaseDeclarations, and \a +// UDMapperList in MVLI. \a MapType, \a IsMapTypeImplicit, \a MapperIdScopeSpec, +// and \a MapperId are expected to be valid if the clause kind is 'map'. +static void checkMappableExpressionList( + Sema &SemaRef, DSAStackTy *DSAS, OpenMPClauseKind CKind, + MappableVarListInfo &MVLI, SourceLocation StartLoc, + CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId, + ArrayRef<Expr *> UnresolvedMappers, + OpenMPMapClauseKind MapType = OMPC_MAP_unknown, + bool IsMapTypeImplicit = false) { // We only expect mappable expressions in 'to', 'from', and 'map' clauses. assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && "Unexpected clause kind with mappable expressions!"); + // If the identifier of user-defined mapper is not specified, it is "default". + // We do not change the actual name in this clause to distinguish whether a + // mapper is specified explicitly, i.e., it is not explicitly specified when + // MapperId.getName() is empty. + if (!MapperId.getName() || MapperId.getName().isEmpty()) { + auto &DeclNames = SemaRef.getASTContext().DeclarationNames; + MapperId.setName(DeclNames.getIdentifier( + &SemaRef.getASTContext().Idents.get("default"))); + } + + // Iterators to find the current unresolved mapper expression. + auto UMIt = UnresolvedMappers.begin(), UMEnd = UnresolvedMappers.end(); + bool UpdateUMIt = false; + Expr *UnresolvedMapper = nullptr; + // Keep track of the mappable components and base declarations in this clause. // Each entry in the list is going to have a list of components associated. We // record each set of the components so that we can build the clause later on. @@ -12932,11 +13914,29 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, assert(RE && "Null expr in omp to/from/map clause"); SourceLocation ELoc = RE->getExprLoc(); + // Find the current unresolved mapper expression. + if (UpdateUMIt && UMIt != UMEnd) { + UMIt++; + assert( + UMIt != UMEnd && + "Expect the size of UnresolvedMappers to match with that of VarList"); + } + UpdateUMIt = true; + if (UMIt != UMEnd) + UnresolvedMapper = *UMIt; + const Expr *VE = RE->IgnoreParenLValueCasts(); if (VE->isValueDependent() || VE->isTypeDependent() || VE->isInstantiationDependent() || VE->containsUnexpandedParameterPack()) { + // Try to find the associated user-defined mapper. + ExprResult ER = buildUserDefinedMapperRef( + SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId, + VE->getType().getCanonicalType(), UnresolvedMapper); + if (ER.isInvalid()) + continue; + MVLI.UDMapperList.push_back(ER.get()); // We can only analyze this information once the missing information is // resolved. MVLI.ProcessedVarList.push_back(RE); @@ -12968,6 +13968,13 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, if (const auto *TE = dyn_cast<CXXThisExpr>(BE)) { // Add store "this" pointer to class in DSAStackTy for future checking DSAS->addMappedClassesQualTypes(TE->getType()); + // Try to find the associated user-defined mapper. + ExprResult ER = buildUserDefinedMapperRef( + SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId, + VE->getType().getCanonicalType(), UnresolvedMapper); + if (ER.isInvalid()) + continue; + MVLI.UDMapperList.push_back(ER.get()); // Skip restriction checking for variable or field declarations MVLI.ProcessedVarList.push_back(RE); MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1); @@ -13086,6 +14093,14 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, } } + // Try to find the associated user-defined mapper. + ExprResult ER = buildUserDefinedMapperRef( + SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId, + Type.getCanonicalType(), UnresolvedMapper); + if (ER.isInvalid()) + continue; + MVLI.UDMapperList.push_back(ER.get()); + // Save the current expression. MVLI.ProcessedVarList.push_back(RE); @@ -13105,19 +14120,16 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, } } -OMPClause * -Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, - ArrayRef<SourceLocation> MapTypeModifiersLoc, - OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, - SourceLocation MapLoc, SourceLocation ColonLoc, - ArrayRef<Expr *> VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { - MappableVarListInfo MVLI(VarList); - checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc, - MapType, IsMapTypeImplicit); - - OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown, - OMPC_MAP_MODIFIER_unknown }; +OMPClause *Sema::ActOnOpenMPMapClause( + ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, + ArrayRef<SourceLocation> MapTypeModifiersLoc, + CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) { + OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown, + OMPC_MAP_MODIFIER_unknown, + OMPC_MAP_MODIFIER_unknown}; SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers]; // Process map-type-modifiers, flag errors for duplicate modifiers. @@ -13135,12 +14147,18 @@ Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, ++Count; } + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, Locs.StartLoc, + MapperIdScopeSpec, MapperId, UnresolvedMappers, + MapType, IsMapTypeImplicit); + // We need to produce a map clause even if we don't have variables so that // other diagnostics related with non-existing map clauses are accurate. - return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, - MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, - MVLI.VarComponents, Modifiers, ModifiersLoc, - MapType, IsMapTypeImplicit, MapLoc); + return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, MVLI.VarComponents, + MVLI.UDMapperList, Modifiers, ModifiersLoc, + MapperIdScopeSpec.getWithLocInContext(Context), + MapperId, MapType, IsMapTypeImplicit, MapLoc); } QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, @@ -13400,6 +14418,143 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( return DeclReductions; } +TypeResult Sema::ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D) { + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType T = TInfo->getType(); + if (D.isInvalidType()) + return true; + + if (getLangOpts().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + return CreateParsedType(T, TInfo); +} + +QualType Sema::ActOnOpenMPDeclareMapperType(SourceLocation TyLoc, + TypeResult ParsedType) { + assert(ParsedType.isUsable() && "Expect usable parsed mapper type"); + + QualType MapperType = GetTypeFromParser(ParsedType.get()); + assert(!MapperType.isNull() && "Expect valid mapper type"); + + // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions + // The type must be of struct, union or class type in C and C++ + if (!MapperType->isStructureOrClassType() && !MapperType->isUnionType()) { + Diag(TyLoc, diag::err_omp_mapper_wrong_type); + return QualType(); + } + return MapperType; +} + +OMPDeclareMapperDecl *Sema::ActOnOpenMPDeclareMapperDirectiveStart( + Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType, + SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS, + Decl *PrevDeclInScope) { + LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPMapperName, + forRedeclarationInCurContext()); + // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions + // A mapper-identifier may not be redeclared in the current scope for the + // same type or for a type that is compatible according to the base language + // rules. + llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes; + OMPDeclareMapperDecl *PrevDMD = nullptr; + bool InCompoundScope = true; + if (S != nullptr) { + // Find previous declaration with the same name not referenced in other + // declarations. + FunctionScopeInfo *ParentFn = getEnclosingFunction(); + InCompoundScope = + (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty(); + LookupName(Lookup, S); + FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + llvm::DenseMap<OMPDeclareMapperDecl *, bool> UsedAsPrevious; + LookupResult::Filter Filter = Lookup.makeFilter(); + while (Filter.hasNext()) { + auto *PrevDecl = cast<OMPDeclareMapperDecl>(Filter.next()); + if (InCompoundScope) { + auto I = UsedAsPrevious.find(PrevDecl); + if (I == UsedAsPrevious.end()) + UsedAsPrevious[PrevDecl] = false; + if (OMPDeclareMapperDecl *D = PrevDecl->getPrevDeclInScope()) + UsedAsPrevious[D] = true; + } + PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] = + PrevDecl->getLocation(); + } + Filter.done(); + if (InCompoundScope) { + for (const auto &PrevData : UsedAsPrevious) { + if (!PrevData.second) { + PrevDMD = PrevData.first; + break; + } + } + } + } else if (PrevDeclInScope) { + auto *PrevDMDInScope = PrevDMD = + cast<OMPDeclareMapperDecl>(PrevDeclInScope); + do { + PreviousRedeclTypes[PrevDMDInScope->getType().getCanonicalType()] = + PrevDMDInScope->getLocation(); + PrevDMDInScope = PrevDMDInScope->getPrevDeclInScope(); + } while (PrevDMDInScope != nullptr); + } + const auto I = PreviousRedeclTypes.find(MapperType.getCanonicalType()); + bool Invalid = false; + if (I != PreviousRedeclTypes.end()) { + Diag(StartLoc, diag::err_omp_declare_mapper_redefinition) + << MapperType << Name; + Diag(I->second, diag::note_previous_definition); + Invalid = true; + } + auto *DMD = OMPDeclareMapperDecl::Create(Context, DC, StartLoc, Name, + MapperType, VN, PrevDMD); + DC->addDecl(DMD); + DMD->setAccess(AS); + if (Invalid) + DMD->setInvalidDecl(); + + // Enter new function scope. + PushFunctionScope(); + setFunctionHasBranchProtectedScope(); + + CurContext = DMD; + + return DMD; +} + +void Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD, + Scope *S, + QualType MapperType, + SourceLocation StartLoc, + DeclarationName VN) { + VarDecl *VD = buildVarDecl(*this, StartLoc, MapperType, VN.getAsString()); + if (S) + PushOnScopeChains(VD, S); + else + DMD->addDecl(VD); + Expr *MapperVarRefExpr = buildDeclRefExpr(*this, VD, MapperType, StartLoc); + DMD->setMapperVarRef(MapperVarRefExpr); +} + +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S, + ArrayRef<OMPClause *> ClauseList) { + PopDeclContext(); + PopFunctionScopeInfo(); + + if (D) { + if (S) + PushOnScopeChains(D, S, /*AddToContext=*/false); + D->CreateClauses(Context, ClauseList); + } + + return DeclGroupPtrTy::make(DeclGroupRef(D)); +} + OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -13632,9 +14787,9 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, Lookup.suppressDiagnostics(); if (!Lookup.isSingleResult()) { + VarOrFuncDeclFilterCCC CCC(*this); if (TypoCorrection Corrected = - CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, - llvm::make_unique<VarOrFuncDeclFilterCCC>(*this), + CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC, CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Id.getName()); @@ -13744,37 +14899,41 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, } OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, + const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers) { MappableVarListInfo MVLI(VarList); - checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc); + checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, Locs.StartLoc, + MapperIdScopeSpec, MapperId, UnresolvedMappers); if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc, - MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, - MVLI.VarComponents); + return OMPToClause::Create( + Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MVLI.UDMapperList, + MapperIdScopeSpec.getWithLocInContext(Context), MapperId); } OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, + const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers) { MappableVarListInfo MVLI(VarList); - checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc); + checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, Locs.StartLoc, + MapperIdScopeSpec, MapperId, UnresolvedMappers); if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc, - MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, - MVLI.VarComponents); + return OMPFromClause::Create( + Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MVLI.UDMapperList, + MapperIdScopeSpec.getWithLocInContext(Context), MapperId); } OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); SmallVector<Expr *, 8> PrivateCopies; SmallVector<Expr *, 8> Inits; @@ -13854,14 +15013,12 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, return nullptr; return OMPUseDevicePtrClause::Create( - Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList, - PrivateCopies, Inits, MVLI.VarBaseDeclarations, MVLI.VarComponents); + Context, Locs, MVLI.ProcessedVarList, PrivateCopies, Inits, + MVLI.VarBaseDeclarations, MVLI.VarComponents); } OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { + const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause."); @@ -13937,7 +15094,68 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPIsDevicePtrClause::Create( - Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList, - MVLI.VarBaseDeclarations, MVLI.VarComponents); + return OMPIsDevicePtrClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + +OMPClause *Sema::ActOnOpenMPAllocateClause( + Expr *Allocator, ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { + if (Allocator) { + // OpenMP [2.11.4 allocate Clause, Description] + // allocator is an expression of omp_allocator_handle_t type. + if (!findOMPAllocatorHandleT(*this, Allocator->getExprLoc(), DSAStack)) + return nullptr; + + ExprResult AllocatorRes = DefaultLvalueConversion(Allocator); + if (AllocatorRes.isInvalid()) + return nullptr; + AllocatorRes = PerformImplicitConversion(AllocatorRes.get(), + DSAStack->getOMPAllocatorHandleT(), + Sema::AA_Initializing, + /*AllowExplicit=*/true); + if (AllocatorRes.isInvalid()) + return nullptr; + Allocator = AllocatorRes.get(); + } else { + // OpenMP 5.0, 2.11.4 allocate Clause, Restrictions. + // allocate clauses that appear on a target construct or on constructs in a + // target region must specify an allocator expression unless a requires + // directive with the dynamic_allocators clause is present in the same + // compilation unit. + if (LangOpts.OpenMPIsDevice && + !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>()) + targetDiag(StartLoc, diag::err_expected_allocator_expression); + } + // Analyze and build list of variables. + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP private clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + auto *VD = dyn_cast<VarDecl>(D); + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); + } + + if (Vars.empty()) + return nullptr; + + return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator, + ColonLoc, EndLoc, Vars); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 52be0598fb..df979b68b6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1,9 +1,8 @@ //===--- SemaOverload.cpp - C++ Overloading -------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -1057,6 +1056,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, // third bullet. If the type of the friend is dependent, skip this lookup // until instantiation. if (New->getFriendObjectKind() && New->getQualifier() && + !New->getDescribedFunctionTemplate() && !New->getDependentSpecializationInfo() && !New->getType()->isDependentType()) { LookupResult TemplateSpecResult(LookupResult::Temporary, Old); @@ -1172,16 +1172,14 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // function yet (because we haven't yet resolved whether this is a static // or non-static member function). Add it now, on the assumption that this // is a redeclaration of OldMethod. - // FIXME: OpenCL: Need to consider address spaces - unsigned OldQuals = OldMethod->getTypeQualifiers().getCVRUQualifiers(); - unsigned NewQuals = NewMethod->getTypeQualifiers().getCVRUQualifiers(); + auto OldQuals = OldMethod->getMethodQualifiers(); + auto NewQuals = NewMethod->getMethodQualifiers(); if (!getLangOpts().CPlusPlus14 && NewMethod->isConstexpr() && !isa<CXXConstructorDecl>(NewMethod)) - NewQuals |= Qualifiers::Const; - + NewQuals.addConst(); // We do not allow overloading based off of '__restrict'. - OldQuals &= ~Qualifiers::Restrict; - NewQuals &= ~Qualifiers::Restrict; + OldQuals.removeRestrict(); + NewQuals.removeRestrict(); if (OldQuals != NewQuals) return true; } @@ -1232,24 +1230,6 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return false; } -/// Checks availability of the function depending on the current -/// function context. Inside an unavailable function, unavailability is ignored. -/// -/// \returns true if \arg FD is unavailable and current context is inside -/// an available function, false otherwise. -bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) { - if (!FD->isUnavailable()) - return false; - - // Walk up the context of the caller. - Decl *C = cast<Decl>(CurContext); - do { - if (C->isUnavailable()) - return false; - } while ((C = cast_or_null<Decl>(C->getDeclContext()))); - return true; -} - /// Tries a user-defined conversion from From to ToType. /// /// Produces an implicit conversion sequence for when a standard conversion @@ -2547,7 +2527,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // function types are obviously different. if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() || FromFunctionType->isVariadic() != ToFunctionType->isVariadic() || - FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals()) + FromFunctionType->getMethodQuals() != ToFunctionType->getMethodQuals()) return false; bool HasObjCConversion = false; @@ -2854,9 +2834,9 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, return; } - if (FromFunction->getTypeQuals() != ToFunction->getTypeQuals()) { - PDiag << ft_qualifer_mismatch << ToFunction->getTypeQuals() - << FromFunction->getTypeQuals(); + if (FromFunction->getMethodQuals() != ToFunction->getMethodQuals()) { + PDiag << ft_qualifer_mismatch << ToFunction->getMethodQuals() + << FromFunction->getMethodQuals(); return; } @@ -3525,18 +3505,25 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { OverloadingResult OvResult = IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined, CandidateSet, false, false); + + if (!(OvResult == OR_Ambiguous || + (OvResult == OR_No_Viable_Function && !CandidateSet.empty()))) + return false; + + auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, From); if (OvResult == OR_Ambiguous) Diag(From->getBeginLoc(), diag::err_typecheck_ambiguous_condition) << From->getType() << ToType << From->getSourceRange(); - else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) { + else { // OR_No_Viable_Function && !CandidateSet.empty() if (!RequireCompleteType(From->getBeginLoc(), ToType, diag::err_typecheck_nonviable_condition_incomplete, From->getType(), From->getSourceRange())) Diag(From->getBeginLoc(), diag::err_typecheck_nonviable_condition) << false << From->getType() << From->getSourceRange() << ToType; - } else - return false; - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, From); + } + + CandidateSet.NoteCandidates( + *this, From, Cands); return true; } @@ -4019,9 +4006,12 @@ CompareQualificationConversions(Sema &S, // to unwrap. This essentially mimics what // IsQualificationConversion does, but here we're checking for a // strict subset of qualifiers. - if (T1.getCVRQualifiers() == T2.getCVRQualifiers()) + if (T1.getQualifiers().withoutObjCLifetime() == + T2.getQualifiers().withoutObjCLifetime()) // The qualifiers are the same, so this doesn't tell us anything // about how the sequences rank. + // ObjC ownership quals are omitted above as they interfere with + // the ARC overload rule. ; else if (T2.isMoreQualifiedThan(T1)) { // T1 has fewer qualifiers, so it could be the better sequence. @@ -5100,7 +5090,7 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType, Quals.addConst(); Quals.addVolatile(); } else { - Quals = Method->getTypeQualifiers(); + Quals = Method->getMethodQualifiers(); } QualType ImplicitParamType = S.Context.getQualifiedType(ClassType, Quals); @@ -5148,6 +5138,16 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType, return ICS; } + if (FromTypeCanon.getQualifiers().hasAddressSpace()) { + Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers(); + Qualifiers QualsFromType = FromTypeCanon.getQualifiers(); + if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) { + ICS.setBad(BadConversionSequence::bad_qualifiers, + FromType, ImplicitParamType); + return ICS; + } + } + // Check that we have either the same type or a derived type. It // affects the conversion rank. QualType ClassTypeCanon = S.Context.getCanonicalType(ClassType); @@ -5286,12 +5286,12 @@ Sema::PerformObjectArgumentInitialization(Expr *From, } if (!Context.hasSameType(From->getType(), DestType)) { - if (From->getType().getAddressSpace() != DestType.getAddressSpace()) - From = ImpCastExprToType(From, DestType, CK_AddressSpaceConversion, - From->getValueKind()).get(); + CastKind CK; + if (FromRecordType.getAddressSpace() != DestType.getAddressSpace()) + CK = CK_AddressSpaceConversion; else - From = ImpCastExprToType(From, DestType, CK_NoOp, - From->getValueKind()).get(); + CK = CK_NoOp; + From = ImpCastExprToType(From, DestType, CK, From->getValueKind()).get(); } return From; } @@ -7649,6 +7649,12 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } } } +/// Helper function for adjusting address spaces for the pointer or reference +/// operands of builtin operators depending on the argument. +static QualType AdjustAddressSpaceForBuiltinOperandType(Sema &S, QualType T, + Expr *Arg) { + return S.Context.getAddrSpaceQualType(T, Arg->getType().getAddressSpace()); +} /// Helper function for AddBuiltinOperatorCandidates() that adds /// the volatile- and non-volatile-qualified assignment operators for the @@ -7660,15 +7666,17 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, QualType ParamTypes[2]; // T& operator=(T&, T) - ParamTypes[0] = S.Context.getLValueReferenceType(T); + ParamTypes[0] = S.Context.getLValueReferenceType( + AdjustAddressSpaceForBuiltinOperandType(S, T, Args[0])); ParamTypes[1] = T; S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/true); if (!S.Context.getCanonicalType(T).isVolatileQualified()) { // volatile T& operator=(volatile T&, T) - ParamTypes[0] - = S.Context.getLValueReferenceType(S.Context.getVolatileType(T)); + ParamTypes[0] = S.Context.getLValueReferenceType( + AdjustAddressSpaceForBuiltinOperandType(S, S.Context.getVolatileType(T), + Args[0])); ParamTypes[1] = T; S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/true); @@ -7947,7 +7955,7 @@ public: continue; if (const FunctionProtoType *Proto =PointeeTy->getAs<FunctionProtoType>()) - if (Proto->getTypeQuals() || Proto->getRefQualifier()) + if (Proto->getMethodQuals() || Proto->getRefQualifier()) continue; S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet); @@ -8495,17 +8503,16 @@ public: Right < LastPromotedArithmeticType; ++Right) { QualType ParamTypes[2]; ParamTypes[1] = ArithmeticTypes[Right]; - + auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType( + S, ArithmeticTypes[Left], Args[0]); // Add this built-in operator as a candidate (VQ is empty). - ParamTypes[0] = - S.Context.getLValueReferenceType(ArithmeticTypes[Left]); + ParamTypes[0] = S.Context.getLValueReferenceType(LeftBaseTy); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { - ParamTypes[0] = - S.Context.getVolatileType(ArithmeticTypes[Left]); + ParamTypes[0] = S.Context.getVolatileType(LeftBaseTy); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); @@ -8561,14 +8568,14 @@ public: Right < LastPromotedIntegralType; ++Right) { QualType ParamTypes[2]; ParamTypes[1] = ArithmeticTypes[Right]; - + auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType( + S, ArithmeticTypes[Left], Args[0]); // Add this built-in operator as a candidate (VQ is empty). - ParamTypes[0] = - S.Context.getLValueReferenceType(ArithmeticTypes[Left]); + ParamTypes[0] = S.Context.getLValueReferenceType(LeftBaseTy); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); if (VisibleTypeConversionsQuals.hasVolatile()) { // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = ArithmeticTypes[Left]; + ParamTypes[0] = LeftBaseTy; ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); @@ -9436,9 +9443,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, } // Best is the best viable function. - if (Best->Function && - (Best->Function->isDeleted() || - S.isFunctionConsideredUnavailable(Best->Function))) + if (Best->Function && Best->Function->isDeleted()) return OR_Deleted; if (!EquivalentCands.empty()) @@ -10350,7 +10355,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, // Note deleted candidates, but only if they're viable. if (Cand->Viable) { - if (Fn->isDeleted() || S.isFunctionConsideredUnavailable(Fn)) { + if (Fn->isDeleted()) { std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); @@ -10747,11 +10752,9 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, } } -/// When overload resolution fails, prints diagnostic messages containing the -/// candidates in the candidate set. -void OverloadCandidateSet::NoteCandidates( +SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates( Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, - StringRef Opc, SourceLocation OpLoc, + SourceLocation OpLoc, llvm::function_ref<bool(OverloadCandidate &)> Filter) { // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. @@ -10771,15 +10774,35 @@ void OverloadCandidateSet::NoteCandidates( } } - std::stable_sort(Cands.begin(), Cands.end(), - CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind)); + llvm::stable_sort( + Cands, CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind)); + + return Cands; +} + +/// When overload resolution fails, prints diagnostic messages containing the +/// candidates in the candidate set. +void OverloadCandidateSet::NoteCandidates(PartialDiagnosticAt PD, + Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, + StringRef Opc, SourceLocation OpLoc, + llvm::function_ref<bool(OverloadCandidate &)> Filter) { + + auto Cands = CompleteCandidates(S, OCD, Args, OpLoc, Filter); + S.Diag(PD.first, PD.second); + + NoteCandidates(S, Args, Cands, Opc, OpLoc); +} + +void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args, + ArrayRef<OverloadCandidate *> Cands, + StringRef Opc, SourceLocation OpLoc) { bool ReportedAmbiguousConversions = false; - SmallVectorImpl<OverloadCandidate*>::iterator I, E; const OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); unsigned CandsShown = 0; - for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { + auto I = Cands.begin(), E = Cands.end(); + for (; I != E; ++I) { OverloadCandidate *Cand = *I; // Set an arbitrary limit on the number of candidate functions we'll spam @@ -11895,15 +11918,6 @@ public: } -static std::unique_ptr<CorrectionCandidateCallback> -MakeValidator(Sema &SemaRef, MemberExpr *ME, size_t NumArgs, - bool HasTemplateArgs, bool AllowTypoCorrection) { - if (!AllowTypoCorrection) - return llvm::make_unique<NoTypoCorrectionCCC>(); - return llvm::make_unique<FunctionCallFilterCCC>(SemaRef, NumArgs, - HasTemplateArgs, ME); -} - /// Attempts to recover from a call where no functions were found. /// /// Returns true if new candidates were found. @@ -11938,16 +11952,22 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); bool DoDiagnoseEmptyLookup = EmptyLookup; - if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, - OverloadCandidateSet::CSK_Normal, - ExplicitTemplateArgs, Args, - &DoDiagnoseEmptyLookup) && - (!DoDiagnoseEmptyLookup || SemaRef.DiagnoseEmptyLookup( - S, SS, R, - MakeValidator(SemaRef, dyn_cast<MemberExpr>(Fn), Args.size(), - ExplicitTemplateArgs != nullptr, AllowTypoCorrection), - ExplicitTemplateArgs, Args))) - return ExprError(); + if (!DiagnoseTwoPhaseLookup( + SemaRef, Fn->getExprLoc(), SS, R, OverloadCandidateSet::CSK_Normal, + ExplicitTemplateArgs, Args, &DoDiagnoseEmptyLookup)) { + NoTypoCorrectionCCC NoTypoValidator{}; + FunctionCallFilterCCC FunctionCallValidator(SemaRef, Args.size(), + ExplicitTemplateArgs != nullptr, + dyn_cast<MemberExpr>(Fn)); + CorrectionCandidateCallback &Validator = + AllowTypoCorrection + ? static_cast<CorrectionCandidateCallback &>(FunctionCallValidator) + : static_cast<CorrectionCandidateCallback &>(NoTypoValidator); + if (!DoDiagnoseEmptyLookup || + SemaRef.DiagnoseEmptyLookup(S, SS, R, Validator, ExplicitTemplateArgs, + Args)) + return ExprError(); + } assert(!R.empty() && "lookup results empty despite recovery"); @@ -12101,24 +12121,29 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, } } - SemaRef.Diag(Fn->getBeginLoc(), diag::err_ovl_no_viable_function_in_call) - << ULE->getName() << Fn->getSourceRange(); - CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args); + CandidateSet->NoteCandidates( + PartialDiagnosticAt( + Fn->getBeginLoc(), + SemaRef.PDiag(diag::err_ovl_no_viable_function_in_call) + << ULE->getName() << Fn->getSourceRange()), + SemaRef, OCD_AllCandidates, Args); break; } case OR_Ambiguous: - SemaRef.Diag(Fn->getBeginLoc(), diag::err_ovl_ambiguous_call) - << ULE->getName() << Fn->getSourceRange(); - CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates, Args); + CandidateSet->NoteCandidates( + PartialDiagnosticAt(Fn->getBeginLoc(), + SemaRef.PDiag(diag::err_ovl_ambiguous_call) + << ULE->getName() << Fn->getSourceRange()), + SemaRef, OCD_ViableCandidates, Args); break; case OR_Deleted: { - SemaRef.Diag(Fn->getBeginLoc(), diag::err_ovl_deleted_call) - << (*Best)->Function->isDeleted() << ULE->getName() - << SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function) - << Fn->getSourceRange(); - CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args); + CandidateSet->NoteCandidates( + PartialDiagnosticAt(Fn->getBeginLoc(), + SemaRef.PDiag(diag::err_ovl_deleted_call) + << ULE->getName() << Fn->getSourceRange()), + SemaRef, OCD_AllCandidates, Args); // We emitted an error for the unavailable/deleted function call but keep // the call in the AST. @@ -12352,22 +12377,22 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, break; case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary) - << UnaryOperator::getOpcodeStr(Opc) - << Input->getType() - << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, ArgsArray, - UnaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(OpLoc, + PDiag(diag::err_ovl_ambiguous_oper_unary) + << UnaryOperator::getOpcodeStr(Opc) + << Input->getType() << Input->getSourceRange()), + *this, OCD_ViableCandidates, ArgsArray, + UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); case OR_Deleted: - Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << UnaryOperator::getOpcodeStr(Opc) - << getDeletedOrUnavailableSuffix(Best->Function) - << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, ArgsArray, - UnaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper) + << UnaryOperator::getOpcodeStr(Opc) + << Input->getSourceRange()), + *this, OCD_AllCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc), + OpLoc); return ExprError(); } @@ -12601,6 +12626,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // operator do not fall through to handling in built-in, but report that // no overloaded assignment operator found ExprResult Result = ExprError(); + StringRef OpcStr = BinaryOperator::getOpcodeStr(Opc); + auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, + Args, OpLoc); if (Args[0]->getType()->isRecordType() && Opc >= BO_Assign && Opc <= BO_OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) @@ -12625,19 +12653,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); - if (Result.isInvalid()) - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, - BinaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates(*this, Args, Cands, OpcStr, OpLoc); return Result; } case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper_binary) - << BinaryOperator::getOpcodeStr(Opc) - << Args[0]->getType() << Args[1]->getType() - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, - BinaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_binary) + << BinaryOperator::getOpcodeStr(Opc) + << Args[0]->getType() + << Args[1]->getType() + << Args[0]->getSourceRange() + << Args[1]->getSourceRange()), + *this, OCD_ViableCandidates, Args, BinaryOperator::getOpcodeStr(Opc), + OpLoc); return ExprError(); case OR_Deleted: @@ -12651,15 +12680,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // explain why it's deleted. NoteDeletedFunction(Method); return ExprError(); - } else { - Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << BinaryOperator::getOpcodeStr(Opc) - << getDeletedOrUnavailableSuffix(Best->Function) - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); } - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, - BinaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper) + << BinaryOperator::getOpcodeStr(Opc) + << Args[0]->getSourceRange() + << Args[1]->getSourceRange()), + *this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc), + OpLoc); return ExprError(); } @@ -12801,35 +12829,34 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, } case OR_No_Viable_Function: { - if (CandidateSet.empty()) - Diag(LLoc, diag::err_ovl_no_oper) - << Args[0]->getType() << /*subscript*/ 0 - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - else - Diag(LLoc, diag::err_ovl_no_viable_subscript) - << Args[0]->getType() - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, - "[]", LLoc); + PartialDiagnostic PD = CandidateSet.empty() + ? (PDiag(diag::err_ovl_no_oper) + << Args[0]->getType() << /*subscript*/ 0 + << Args[0]->getSourceRange() << Args[1]->getSourceRange()) + : (PDiag(diag::err_ovl_no_viable_subscript) + << Args[0]->getType() << Args[0]->getSourceRange() + << Args[1]->getSourceRange()); + CandidateSet.NoteCandidates(PartialDiagnosticAt(LLoc, PD), *this, + OCD_AllCandidates, Args, "[]", LLoc); return ExprError(); } case OR_Ambiguous: - Diag(LLoc, diag::err_ovl_ambiguous_oper_binary) - << "[]" - << Args[0]->getType() << Args[1]->getType() - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, - "[]", LLoc); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary) + << "[]" << Args[0]->getType() + << Args[1]->getType() + << Args[0]->getSourceRange() + << Args[1]->getSourceRange()), + *this, OCD_ViableCandidates, Args, "[]", LLoc); return ExprError(); case OR_Deleted: - Diag(LLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() << "[]" - << getDeletedOrUnavailableSuffix(Best->Function) - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, - "[]", LLoc); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_deleted_oper) + << "[]" << Args[0]->getSourceRange() + << Args[1]->getSourceRange()), + *this, OCD_AllCandidates, Args, "[]", LLoc); return ExprError(); } @@ -12870,7 +12897,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Check that the object type isn't more qualified than the // member function we're calling. - Qualifiers funcQuals = proto->getTypeQuals(); + Qualifiers funcQuals = proto->getMethodQuals(); QualType objectType = op->getLHS()->getType(); if (op->getOpcode() == BO_PtrMemI) @@ -12998,27 +13025,30 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, break; case OR_No_Viable_Function: - Diag(UnresExpr->getMemberLoc(), - diag::err_ovl_no_viable_member_function_in_call) - << DeclName << MemExprE->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt( + UnresExpr->getMemberLoc(), + PDiag(diag::err_ovl_no_viable_member_function_in_call) + << DeclName << MemExprE->getSourceRange()), + *this, OCD_AllCandidates, Args); // FIXME: Leaking incoming expressions! return ExprError(); case OR_Ambiguous: - Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) - << DeclName << MemExprE->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(UnresExpr->getMemberLoc(), + PDiag(diag::err_ovl_ambiguous_member_call) + << DeclName << MemExprE->getSourceRange()), + *this, OCD_AllCandidates, Args); // FIXME: Leaking incoming expressions! return ExprError(); case OR_Deleted: - Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) - << Best->Function->isDeleted() - << DeclName - << getDeletedOrUnavailableSuffix(Best->Function) - << MemExprE->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(UnresExpr->getMemberLoc(), + PDiag(diag::err_ovl_deleted_member_call) + << DeclName << MemExprE->getSourceRange()), + *this, OCD_AllCandidates, Args); // FIXME: Leaking incoming expressions! return ExprError(); } @@ -13222,29 +13252,35 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // below. break; - case OR_No_Viable_Function: - if (CandidateSet.empty()) - Diag(Object.get()->getBeginLoc(), diag::err_ovl_no_oper) - << Object.get()->getType() << /*call*/ 1 - << Object.get()->getSourceRange(); - else - Diag(Object.get()->getBeginLoc(), diag::err_ovl_no_viable_object_call) - << Object.get()->getType() << Object.get()->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args); + case OR_No_Viable_Function: { + PartialDiagnostic PD = + CandidateSet.empty() + ? (PDiag(diag::err_ovl_no_oper) + << Object.get()->getType() << /*call*/ 1 + << Object.get()->getSourceRange()) + : (PDiag(diag::err_ovl_no_viable_object_call) + << Object.get()->getType() << Object.get()->getSourceRange()); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(Object.get()->getBeginLoc(), PD), *this, + OCD_AllCandidates, Args); break; - + } case OR_Ambiguous: - Diag(Object.get()->getBeginLoc(), diag::err_ovl_ambiguous_object_call) - << Object.get()->getType() << Object.get()->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(Object.get()->getBeginLoc(), + PDiag(diag::err_ovl_ambiguous_object_call) + << Object.get()->getType() + << Object.get()->getSourceRange()), + *this, OCD_ViableCandidates, Args); break; case OR_Deleted: - Diag(Object.get()->getBeginLoc(), diag::err_ovl_deleted_object_call) - << Best->Function->isDeleted() << Object.get()->getType() - << getDeletedOrUnavailableSuffix(Best->Function) - << Object.get()->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(Object.get()->getBeginLoc(), + PDiag(diag::err_ovl_deleted_object_call) + << Object.get()->getType() + << Object.get()->getSourceRange()), + *this, OCD_AllCandidates, Args); break; } @@ -13443,7 +13479,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, // Overload resolution succeeded; we'll build the call below. break; - case OR_No_Viable_Function: + case OR_No_Viable_Function: { + auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, Base); if (CandidateSet.empty()) { QualType BaseType = Base->getType(); if (NoArrowOperatorFound) { @@ -13461,22 +13498,22 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, } else Diag(OpLoc, diag::err_ovl_no_viable_oper) << "operator->" << Base->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base); + CandidateSet.NoteCandidates(*this, Base, Cands); return ExprError(); - + } case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary) - << "->" << Base->getType() << Base->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Base); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary) + << "->" << Base->getType() + << Base->getSourceRange()), + *this, OCD_ViableCandidates, Base); return ExprError(); case OR_Deleted: - Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << "->" - << getDeletedOrUnavailableSuffix(Best->Function) - << Base->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper) + << "->" << Base->getSourceRange()), + *this, OCD_AllCandidates, Base); return ExprError(); } @@ -13538,14 +13575,18 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, break; case OR_No_Viable_Function: - Diag(UDSuffixLoc, diag::err_ovl_no_viable_function_in_call) - << R.getLookupName(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(UDSuffixLoc, + PDiag(diag::err_ovl_no_viable_function_in_call) + << R.getLookupName()), + *this, OCD_AllCandidates, Args); return ExprError(); case OR_Ambiguous: - Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(R.getNameLoc(), PDiag(diag::err_ovl_ambiguous_call) + << R.getLookupName()), + *this, OCD_ViableCandidates, Args); return ExprError(); } @@ -13701,7 +13742,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, unsigned ResultIdx = GSE->getResultIndex(); AssocExprs[ResultIdx] = SubExpr; - return new (Context) GenericSelectionExpr( + return GenericSelectionExpr::Create( Context, GSE->getGenericLoc(), GSE->getControllingExpr(), GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(), GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(), diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index ebf1d10aa1..28a4d62b03 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -1,9 +1,8 @@ //===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -141,25 +140,24 @@ namespace { unsigned resultIndex = gse->getResultIndex(); unsigned numAssocs = gse->getNumAssocs(); - SmallVector<Expr*, 8> assocs(numAssocs); - SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs); - - for (unsigned i = 0; i != numAssocs; ++i) { - Expr *assoc = gse->getAssocExpr(i); - if (i == resultIndex) assoc = rebuild(assoc); - assocs[i] = assoc; - assocTypes[i] = gse->getAssocTypeSourceInfo(i); + SmallVector<Expr *, 8> assocExprs; + SmallVector<TypeSourceInfo *, 8> assocTypes; + assocExprs.reserve(numAssocs); + assocTypes.reserve(numAssocs); + + for (const GenericSelectionExpr::Association &assoc : + gse->associations()) { + Expr *assocExpr = assoc.getAssociationExpr(); + if (assoc.isSelected()) + assocExpr = rebuild(assocExpr); + assocExprs.push_back(assocExpr); + assocTypes.push_back(assoc.getTypeSourceInfo()); } - return new (S.Context) GenericSelectionExpr(S.Context, - gse->getGenericLoc(), - gse->getControllingExpr(), - assocTypes, - assocs, - gse->getDefaultLoc(), - gse->getRParenLoc(), - gse->containsUnexpandedParameterPack(), - resultIndex); + return GenericSelectionExpr::Create( + S.Context, gse->getGenericLoc(), gse->getControllingExpr(), + assocTypes, assocExprs, gse->getDefaultLoc(), gse->getRParenLoc(), + gse->containsUnexpandedParameterPack(), resultIndex); } if (ChooseExpr *ce = dyn_cast<ChooseExpr>(e)) { diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9e30c9a396..e9faba6e6b 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1,9 +1,8 @@ //===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -347,10 +346,6 @@ sema::CompoundScopeInfo &Sema::getCurCompoundScope() const { return getCurFunction()->CompoundScopes.back(); } -bool Sema::isCurCompoundStmtAStmtExpr() const { - return getCurCompoundScope().IsStmtExpr; -} - StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef<Stmt *> Elts, bool isStmtExpr) { const unsigned NumElts = Elts.size(); @@ -943,7 +938,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, bool ShouldCheckConstantCond = HasConstantCond; // Sort all the scalar case values so we can easily detect duplicates. - std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); + llvm::stable_sort(CaseVals, CmpCaseVals); if (!CaseVals.empty()) { for (unsigned i = 0, e = CaseVals.size(); i != e; ++i) { @@ -991,7 +986,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (!CaseRanges.empty()) { // Sort all the case ranges by their low value so we can easily detect // overlaps between ranges. - std::stable_sort(CaseRanges.begin(), CaseRanges.end()); + llvm::stable_sort(CaseRanges); // Scan the ranges, computing the high values and removing empty ranges. std::vector<llvm::APSInt> HiVals; @@ -1110,7 +1105,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, AdjustAPSInt(Val, CondWidth, CondIsSigned); EnumVals.push_back(std::make_pair(Val, EDI)); } - std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); + llvm::stable_sort(EnumVals, CmpEnumVals); auto EI = EnumVals.begin(), EIEnd = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); @@ -1167,6 +1162,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, break; } + if (EI->second->hasAttr<UnusedAttr>()) + continue; + // Drop unneeded case values while (CI != CaseVals.end() && CI->first < EI->first) CI++; @@ -1261,7 +1259,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, } if (EnumVals.empty()) return; - std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); + llvm::stable_sort(EnumVals, CmpEnumVals); EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); @@ -2229,9 +2227,11 @@ BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange, return Sema::FRS_Success; case Sema::FRS_NoViableFunction: - SemaRef.Diag(BeginRange->getBeginLoc(), diag::err_for_range_invalid) - << BeginRange->getType() << BEFFound; - CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, BeginRange); + CandidateSet->NoteCandidates( + PartialDiagnosticAt(BeginRange->getBeginLoc(), + SemaRef.PDiag(diag::err_for_range_invalid) + << BeginRange->getType() << BEFFound), + SemaRef, OCD_AllCandidates, BeginRange); LLVM_FALLTHROUGH; case Sema::FRS_DiagnosticIssued: @@ -2528,9 +2528,12 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, // Otherwise, emit diagnostics if we haven't already. if (RangeStatus == FRS_NoViableFunction) { Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get(); - Diag(Range->getBeginLoc(), diag::err_for_range_invalid) - << RangeLoc << Range->getType() << BEFFailure; - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Range); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(Range->getBeginLoc(), + PDiag(diag::err_for_range_invalid) + << RangeLoc << Range->getType() + << BEFFailure), + *this, OCD_AllCandidates, Range); } // Return an error if no fix was discovered. if (RangeStatus != FRS_Success) @@ -3998,12 +4001,10 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef<Stmt *> Handlers) { // Don't report an error if 'try' is used in system headers. if (!getLangOpts().CXXExceptions && - !getSourceManager().isInSystemHeader(TryLoc) && - (!getLangOpts().OpenMPIsDevice || - !getLangOpts().OpenMPHostCXXExceptions || - isInOpenMPTargetExecutionDirective() || - isInOpenMPDeclareTargetContext())) - Diag(TryLoc, diag::err_exceptions_disabled) << "try"; + !getSourceManager().isInSystemHeader(TryLoc) && !getLangOpts().CUDA) { + // Delay error emission for the OpenMP device code. + targetDiag(TryLoc, diag::err_exceptions_disabled) << "try"; + } // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 9e084c99d0..8c6012573c 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -1,9 +1,8 @@ //===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -254,15 +253,6 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // The parser verifies that there is a string literal here. assert(AsmString->isAscii()); - // If we're compiling CUDA file and function attributes indicate that it's not - // for this compilation side, skip all the checks. - if (!DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) { - GCCAsmStmt *NS = new (Context) GCCAsmStmt( - Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, - Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc); - return NS; - } - for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); @@ -272,10 +262,15 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); - if (!Context.getTargetInfo().validateOutputConstraint(Info)) - return StmtError( - Diag(Literal->getBeginLoc(), diag::err_asm_invalid_output_constraint) - << Info.getConstraintStr()); + if (!Context.getTargetInfo().validateOutputConstraint(Info)) { + targetDiag(Literal->getBeginLoc(), + diag::err_asm_invalid_output_constraint) + << Info.getConstraintStr(); + return new (Context) + GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, Constraints, Exprs.data(), AsmString, + NumClobbers, Clobbers, RParenLoc); + } ExprResult ER = CheckPlaceholderExpr(Exprs[i]); if (ER.isInvalid()) @@ -329,10 +324,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, unsigned Size = Context.getTypeSize(OutputExpr->getType()); if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), - Size)) - return StmtError( - Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size) - << Info.getConstraintStr()); + Size)) { + targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size) + << Info.getConstraintStr(); + return new (Context) + GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, Constraints, Exprs.data(), AsmString, + NumClobbers, Clobbers, RParenLoc); + } } SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; @@ -348,9 +347,12 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos, Info)) { - return StmtError( - Diag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint) - << Info.getConstraintStr()); + targetDiag(Literal->getBeginLoc(), diag::err_asm_invalid_input_constraint) + << Info.getConstraintStr(); + return new (Context) + GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, Constraints, Exprs.data(), AsmString, + NumClobbers, Clobbers, RParenLoc); } ExprResult ER = CheckPlaceholderExpr(Exprs[i]); @@ -383,11 +385,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return StmtError( Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) << Info.getConstraintStr() << InputExpr->getSourceRange()); - llvm::APSInt Result = EVResult.Val.getInt(); - if (!Info.isValidAsmImmediate(Result)) + + // For compatibility with GCC, we also allow pointers that would be + // integral constant expressions if they were cast to int. + llvm::APSInt IntResult; + if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + Context)) + return StmtError( + Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) + << Info.getConstraintStr() << InputExpr->getSourceRange()); + + if (!Info.isValidAsmImmediate(IntResult)) return StmtError(Diag(InputExpr->getBeginLoc(), diag::err_invalid_asm_value_for_constraint) - << Result.toString(10) << Info.getConstraintStr() + << IntResult.toString(10) << Info.getConstraintStr() << InputExpr->getSourceRange()); } @@ -422,8 +433,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, unsigned Size = Context.getTypeSize(Ty); if (!Context.getTargetInfo().validateInputSize(Literal->getString(), Size)) - return StmtError( - Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size) + return StmtResult( + targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); } @@ -434,10 +445,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, StringRef Clobber = Literal->getString(); - if (!Context.getTargetInfo().isValidClobber(Clobber)) - return StmtError( - Diag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name) - << Clobber); + if (!Context.getTargetInfo().isValidClobber(Clobber)) { + targetDiag(Literal->getBeginLoc(), diag::err_asm_unknown_register_name) + << Clobber; + return new (Context) + GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, Constraints, Exprs.data(), AsmString, + NumClobbers, Clobbers, RParenLoc); + } } GCCAsmStmt *NS = @@ -449,9 +464,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { - Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) - << AsmString->getSourceRange(); - return StmtError(); + targetDiag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) + << AsmString->getSourceRange(); + return NS; } // Validate constraints and modifiers. @@ -489,16 +504,15 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, if (!Context.getTargetInfo().validateConstraintModifier( Literal->getString(), Piece.getModifier(), Size, SuggestedModifier)) { - Diag(Exprs[ConstraintIdx]->getBeginLoc(), - diag::warn_asm_mismatched_size_modifier); + targetDiag(Exprs[ConstraintIdx]->getBeginLoc(), + diag::warn_asm_mismatched_size_modifier); if (!SuggestedModifier.empty()) { - auto B = Diag(Piece.getRange().getBegin(), - diag::note_asm_missing_constraint_modifier) + auto B = targetDiag(Piece.getRange().getBegin(), + diag::note_asm_missing_constraint_modifier) << SuggestedModifier; SuggestedModifier = "%" + SuggestedModifier + Piece.getString(); - B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(), - SuggestedModifier)); + B << FixItHint::CreateReplacement(Piece.getRange(), SuggestedModifier); } } } @@ -509,12 +523,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; StringRef ConstraintStr = Info.getConstraintStr(); unsigned AltCount = ConstraintStr.count(',') + 1; - if (NumAlternatives == ~0U) + if (NumAlternatives == ~0U) { NumAlternatives = AltCount; - else if (NumAlternatives != AltCount) - return StmtError(Diag(NS->getOutputExpr(i)->getBeginLoc(), - diag::err_asm_unexpected_constraint_alternatives) - << NumAlternatives << AltCount); + } else if (NumAlternatives != AltCount) { + targetDiag(NS->getOutputExpr(i)->getBeginLoc(), + diag::err_asm_unexpected_constraint_alternatives) + << NumAlternatives << AltCount; + return NS; + } } SmallVector<size_t, 4> InputMatchedToOutput(OutputConstraintInfos.size(), ~0U); @@ -522,12 +538,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; StringRef ConstraintStr = Info.getConstraintStr(); unsigned AltCount = ConstraintStr.count(',') + 1; - if (NumAlternatives == ~0U) + if (NumAlternatives == ~0U) { NumAlternatives = AltCount; - else if (NumAlternatives != AltCount) - return StmtError(Diag(NS->getInputExpr(i)->getBeginLoc(), - diag::err_asm_unexpected_constraint_alternatives) - << NumAlternatives << AltCount); + } else if (NumAlternatives != AltCount) { + targetDiag(NS->getInputExpr(i)->getBeginLoc(), + diag::err_asm_unexpected_constraint_alternatives) + << NumAlternatives << AltCount; + return NS; + } // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the @@ -542,13 +560,13 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Make sure no more than one input constraint matches each output. assert(TiedTo < InputMatchedToOutput.size() && "TiedTo value out of range"); if (InputMatchedToOutput[TiedTo] != ~0U) { - Diag(NS->getInputExpr(i)->getBeginLoc(), - diag::err_asm_input_duplicate_match) + targetDiag(NS->getInputExpr(i)->getBeginLoc(), + diag::err_asm_input_duplicate_match) << TiedTo; - Diag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(), - diag::note_asm_input_duplicate_first) + targetDiag(NS->getInputExpr(InputMatchedToOutput[TiedTo])->getBeginLoc(), + diag::note_asm_input_duplicate_first) << TiedTo; - return StmtError(); + return NS; } InputMatchedToOutput[TiedTo] = i; @@ -633,10 +651,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, continue; } - Diag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types) + targetDiag(InputExpr->getBeginLoc(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() << InputExpr->getSourceRange(); - return StmtError(); + return NS; } // Check for conflicts between clobber list and input or output lists @@ -644,7 +662,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers, Context.getTargetInfo(), Context); if (ConstraintLoc.isValid()) - return Diag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); + targetDiag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); return NS; } diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index a8e54b36b2..623f6ef8e8 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -1,9 +1,8 @@ //===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3f9dc98910..58ad439747 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1,9 +1,8 @@ //===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file implements semantic analysis for C++ templates. @@ -67,17 +66,20 @@ static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, /// Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, -/// returns NULL. -static NamedDecl *isAcceptableTemplateName(ASTContext &Context, - NamedDecl *Orig, - bool AllowFunctionTemplates) { - NamedDecl *D = Orig->getUnderlyingDecl(); +/// returns null. +/// +/// Note that this may return an UnresolvedUsingValueDecl if AllowDependent +/// is true. In all other cases it will return a TemplateDecl (or null). +NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D, + bool AllowFunctionTemplates, + bool AllowDependent) { + D = D->getUnderlyingDecl(); if (isa<TemplateDecl>(D)) { if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D)) return nullptr; - return Orig; + return D; } if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { @@ -108,54 +110,29 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, // 'using Dependent::foo;' can resolve to a template name. // 'using typename Dependent::foo;' cannot (not even if 'foo' is an // injected-class-name). - if (isa<UnresolvedUsingValueDecl>(D)) + if (AllowDependent && isa<UnresolvedUsingValueDecl>(D)) return D; return nullptr; } void Sema::FilterAcceptableTemplateNames(LookupResult &R, - bool AllowFunctionTemplates) { - // The set of class templates we've already seen. - llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; + bool AllowFunctionTemplates, + bool AllowDependent) { LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); - NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, - AllowFunctionTemplates); - if (!Repl) + if (!getAsTemplateNameDecl(Orig, AllowFunctionTemplates, AllowDependent)) filter.erase(); - else if (Repl != Orig) { - - // C++ [temp.local]p3: - // A lookup that finds an injected-class-name (10.2) can result in an - // ambiguity in certain cases (for example, if it is found in more than - // one base class). If all of the injected-class-names that are found - // refer to specializations of the same class template, and if the name - // is used as a template-name, the reference refers to the class - // template itself and not a specialization thereof, and is not - // ambiguous. - if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) - if (!ClassTemplates.insert(ClassTmpl).second) { - filter.erase(); - continue; - } - - // FIXME: we promote access to public here as a workaround to - // the fact that LookupResult doesn't let us remember that we - // found this template through a particular injected class name, - // which means we end up doing nasty things to the invariants. - // Pretending that access is public is *much* safer. - filter.replace(Repl, AS_public); - } } filter.done(); } bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, - bool AllowFunctionTemplates) { + bool AllowFunctionTemplates, + bool AllowDependent) { for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) - if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates)) + if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent)) return true; return false; @@ -199,20 +176,45 @@ TemplateNameKind Sema::isTemplateName(Scope *S, MemberOfUnknownSpecialization)) return TNK_Non_template; if (R.empty()) return TNK_Non_template; + + NamedDecl *D = nullptr; if (R.isAmbiguous()) { - // Suppress diagnostics; we'll redo this lookup later. - R.suppressDiagnostics(); + // If we got an ambiguity involving a non-function template, treat this + // as a template name, and pick an arbitrary template for error recovery. + bool AnyFunctionTemplates = false; + for (NamedDecl *FoundD : R) { + if (NamedDecl *FoundTemplate = getAsTemplateNameDecl(FoundD)) { + if (isa<FunctionTemplateDecl>(FoundTemplate)) + AnyFunctionTemplates = true; + else { + D = FoundTemplate; + break; + } + } + } - // FIXME: we might have ambiguous templates, in which case we - // should at least parse them properly! - return TNK_Non_template; + // If we didn't find any templates at all, this isn't a template name. + // Leave the ambiguity for a later lookup to diagnose. + if (!D && !AnyFunctionTemplates) { + R.suppressDiagnostics(); + return TNK_Non_template; + } + + // If the only templates were function templates, filter out the rest. + // We'll diagnose the ambiguity later. + if (!D) + FilterAcceptableTemplateNames(R); } + // At this point, we have either picked a single template name declaration D + // or we have a non-empty set of results R containing either one template name + // declaration or a set of function templates. + TemplateName Template; TemplateNameKind TemplateKind; unsigned ResultCount = R.end() - R.begin(); - if (ResultCount > 1) { + if (!D && ResultCount > 1) { // We assume that we'll preserve the qualifier from a function // template name in other ways. Template = Context.getOverloadedTemplateName(R.begin(), R.end()); @@ -220,12 +222,19 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // We'll do this lookup again later. R.suppressDiagnostics(); - } else if (isa<UnresolvedUsingValueDecl>((*R.begin())->getUnderlyingDecl())) { - // We don't yet know whether this is a template-name or not. - MemberOfUnknownSpecialization = true; - return TNK_Non_template; } else { - TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl()); + if (!D) { + D = getAsTemplateNameDecl(*R.begin()); + assert(D && "unambiguous result is not a template name"); + } + + if (isa<UnresolvedUsingValueDecl>(D)) { + // We don't yet know whether this is a template-name or not. + MemberOfUnknownSpecialization = true; + return TNK_Non_template; + } + + TemplateDecl *TD = cast<TemplateDecl>(D); if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); @@ -317,6 +326,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, bool EnteringContext, bool &MemberOfUnknownSpecialization, SourceLocation TemplateKWLoc) { + Found.setTemplateNameLookup(true); + // Determine where to perform name lookup MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; @@ -391,24 +402,29 @@ bool Sema::LookupTemplateName(LookupResult &Found, IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } + if (Found.isAmbiguous()) + return false; + if (Found.empty() && !IsDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast - auto FilterCCC = llvm::make_unique<CorrectionCandidateCallback>(); - FilterCCC->WantTypeSpecifiers = false; - FilterCCC->WantExpressionKeywords = false; - FilterCCC->WantRemainingKeywords = false; - FilterCCC->WantCXXNamedCasts = true; - if (TypoCorrection Corrected = CorrectTypo( - Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, - std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) { + DefaultFilterCCC FilterCCC{}; + FilterCCC.WantTypeSpecifiers = false; + FilterCCC.WantExpressionKeywords = false; + FilterCCC.WantRemainingKeywords = false; + FilterCCC.WantCXXNamedCasts = true; + if (TypoCorrection Corrected = + CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S, + &SS, FilterCCC, CTK_ErrorRecovery, LookupCtx)) { Found.setLookupName(Corrected.getCorrection()); if (auto *ND = Corrected.getFoundDecl()) Found.addDecl(ND); FilterAcceptableTemplateNames(Found); - if (!Found.empty()) { + if (Found.isAmbiguous()) { + Found.clear(); + } else if (!Found.empty()) { if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && @@ -458,14 +474,19 @@ bool Sema::LookupTemplateName(LookupResult &Found, // Note: C++11 does not perform this second lookup. LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(), LookupOrdinaryName); + FoundOuter.setTemplateNameLookup(true); LookupName(FoundOuter, S); + // FIXME: We silently accept an ambiguous lookup here, in violation of + // [basic.lookup]/1. FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false); + NamedDecl *OuterTemplate; if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise - } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() || - FoundOuter.isAmbiguous()) { + } else if (FoundOuter.isAmbiguous() || !FoundOuter.isSingleResult() || + !(OuterTemplate = + getAsTemplateNameDecl(FoundOuter.getFoundDecl()))) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise @@ -475,8 +496,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. if (!Found.isSingleResult() || - Found.getFoundDecl()->getCanonicalDecl() - != FoundOuter.getFoundDecl()->getCanonicalDecl()) { + getAsTemplateNameDecl(Found.getFoundDecl())->getCanonicalDecl() != + OuterTemplate->getCanonicalDecl()) { Diag(Found.getNameLoc(), diag::ext_nested_name_member_ref_lookup_ambiguous) << Found.getLookupName() @@ -546,7 +567,8 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, // Try to correct the name by looking for templates and C++ named casts. struct TemplateCandidateFilter : CorrectionCandidateCallback { - TemplateCandidateFilter() { + Sema &S; + TemplateCandidateFilter(Sema &S) : S(S) { WantTypeSpecifiers = false; WantExpressionKeywords = false; WantRemainingKeywords = false; @@ -554,20 +576,22 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, }; bool ValidateCandidate(const TypoCorrection &Candidate) override { if (auto *ND = Candidate.getCorrectionDecl()) - return isAcceptableTemplateName(ND->getASTContext(), ND, true); + return S.getAsTemplateNameDecl(ND); return Candidate.isKeyword(); } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<TemplateCandidateFilter>(*this); + } }; DeclarationName Name = NameInfo.getName(); - if (TypoCorrection Corrected = - CorrectTypo(NameInfo, LookupKind, S, &SS, - llvm::make_unique<TemplateCandidateFilter>(), - CTK_ErrorRecovery, LookupCtx)) { + TemplateCandidateFilter CCC(*this); + if (TypoCorrection Corrected = CorrectTypo(NameInfo, LookupKind, S, &SS, CCC, + CTK_ErrorRecovery, LookupCtx)) { auto *ND = Corrected.getFoundDecl(); if (ND) - ND = isAcceptableTemplateName(Context, ND, - /*AllowFunctionTemplates*/ true); + ND = getAsTemplateNameDecl(ND); if (ND || Corrected.isKeyword()) { if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); @@ -3903,13 +3927,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization( Specialization->setAccess(VarTemplate->getAccess()); } - // Link instantiations of static data members back to the template from - // which they were instantiated. - if (Specialization->isStaticDataMember()) - Specialization->setInstantiationOfStaticDataMember( - VarTemplate->getTemplatedDecl(), - Specialization->getSpecializationKind()); - return Specialization; } @@ -4263,7 +4280,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, LookupOrdinaryName); bool MOUS; if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, - MOUS, TemplateKWLoc)) + MOUS, TemplateKWLoc) && !R.isAmbiguous()) Diag(Name.getBeginLoc(), diag::err_no_member) << DNI.getName() << LookupCtx << SS.getRange(); return TNK_Non_template; @@ -6309,7 +6326,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- a predefined __func__ variable if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) { if (isa<CXXUuidofExpr>(E)) { - Converted = TemplateArgument(ArgResult.get()); + Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts()); break; } Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref) @@ -6342,6 +6359,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } case APValue::AddrLabelDiff: return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); + case APValue::FixedPoint: case APValue::Float: case APValue::ComplexInt: case APValue::ComplexFloat: @@ -8594,6 +8612,29 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, return false; } +/// Common checks for whether an explicit instantiation of \p D is valid. +static bool CheckExplicitInstantiation(Sema &S, NamedDecl *D, + SourceLocation InstLoc, + bool WasQualifiedName, + TemplateSpecializationKind TSK) { + // C++ [temp.explicit]p13: + // An explicit instantiation declaration shall not name a specialization of + // a template with internal linkage. + if (TSK == TSK_ExplicitInstantiationDeclaration && + D->getFormalLinkage() == InternalLinkage) { + S.Diag(InstLoc, diag::err_explicit_instantiation_internal_linkage) << D; + return true; + } + + // C++11 [temp.explicit]p3: [DR 275] + // An explicit instantiation shall appear in an enclosing namespace of its + // template. + if (CheckExplicitInstantiationScope(S, D, InstLoc, WasQualifiedName)) + return true; + + return false; +} + /// Determine whether the given scope specifier has a template-id in it. static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { if (!SS.isSet()) @@ -8684,8 +8725,10 @@ DeclResult Sema::ActOnExplicitInstantiation( ? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - if (TSK == TSK_ExplicitInstantiationDeclaration) { - // Check for dllexport class template instantiation declarations. + if (TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation declarations, + // except for MinGW mode. for (const ParsedAttr &AL : Attr) { if (AL.getKind() == ParsedAttr::AT_DLLExport) { Diag(ExternLoc, @@ -8745,13 +8788,21 @@ DeclResult Sema::ActOnExplicitInstantiation( TemplateSpecializationKind PrevDecl_TSK = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared; - // C++0x [temp.explicit]p2: - // [...] An explicit instantiation shall appear in an enclosing - // namespace of its template. [...] - // - // This is C++ DR 275. - if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc, - SS.isSet())) + if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl != nullptr && + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation definitions in MinGW + // mode, if a previous declaration of the instantiation was seen. + for (const ParsedAttr &AL : Attr) { + if (AL.getKind() == ParsedAttr::AT_DLLExport) { + Diag(AL.getLoc(), + diag::warn_attribute_dllexport_explicit_instantiation_def); + break; + } + } + } + + if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc, + SS.isSet(), TSK)) return true; ClassTemplateSpecializationDecl *Specialization = nullptr; @@ -8906,6 +8957,14 @@ DeclResult Sema::ActOnExplicitInstantiation( dllExportImportClassTemplateSpecialization(*this, Def); } + // In MinGW mode, export the template instantiation if the declaration + // was marked dllexport. + if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration && + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() && + PrevDecl->hasAttr<DLLExportAttr>()) { + dllExportImportClassTemplateSpecialization(*this, Def); + } + // Set the template specialization kind. Make sure it is set before // instantiating the members which will trigger ASTConsumer callbacks. Specialization->setTemplateSpecializationKind(TSK); @@ -8974,12 +9033,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - // C++0x [temp.explicit]p2: - // [...] An explicit instantiation shall appear in an enclosing - // namespace of its template. [...] - // - // This is C++ DR 275. - CheckExplicitInstantiationScope(*this, Record, NameLoc, true); + CheckExplicitInstantiation(*this, Record, NameLoc, true, TSK); // Verify that it is okay to explicitly instantiate here. CXXRecordDecl *PrevDecl @@ -9137,7 +9191,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!PrevTemplate) { if (!Prev || !Prev->isStaticDataMember()) { - // We expect to see a data data member here. + // We expect to see a static data member here. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) << Name; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); @@ -9210,8 +9264,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Prev << D.getCXXScopeSpec().getRange(); - // Check the scope of this explicit instantiation. - CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true); + CheckExplicitInstantiation(*this, Prev, D.getIdentifierLoc(), true, TSK); // Verify that it is okay to explicitly instantiate here. TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind(); @@ -9386,6 +9439,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return (Decl*) nullptr; } + // HACK: libc++ has a bug where it attempts to explicitly instantiate the + // functions + // valarray<size_t>::valarray(size_t) and + // valarray<size_t>::~valarray() + // that it declared to have internal linkage with the internal_linkage + // attribute. Ignore the explicit instantiation declaration in this case. + if (Specialization->hasAttr<InternalLinkageAttr>() && + TSK == TSK_ExplicitInstantiationDeclaration) { + if (auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getDeclContext())) + if (RD->getIdentifier() && RD->getIdentifier()->isStr("valarray") && + RD->isInStdNamespace()) + return (Decl*) nullptr; + } + ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes()); // In MSVC mode, dllimported explicit instantiation definitions are treated as @@ -9419,11 +9486,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); - CheckExplicitInstantiationScope(*this, - FunTmpl? (NamedDecl *)FunTmpl - : Specialization->getInstantiatedFromMemberFunction(), - D.getIdentifierLoc(), - D.getCXXScopeSpec().isSet()); + CheckExplicitInstantiation( + *this, + FunTmpl ? (NamedDecl *)FunTmpl + : Specialization->getInstantiatedFromMemberFunction(), + D.getIdentifierLoc(), D.getCXXScopeSpec().isSet(), TSK); // FIXME: Create some kind of ExplicitInstantiationDecl here. return (Decl*) nullptr; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index f2f989ce12..4dccf2f459 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1,9 +1,8 @@ //===- SemaTemplateDeduction.cpp - Template Argument Deduction ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -1671,8 +1670,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, const FunctionProtoType *FunctionProtoParam = cast<FunctionProtoType>(Param); - if (FunctionProtoParam->getTypeQuals() - != FunctionProtoArg->getTypeQuals() || + if (FunctionProtoParam->getMethodQuals() + != FunctionProtoArg->getMethodQuals() || FunctionProtoParam->getRefQualifier() != FunctionProtoArg->getRefQualifier() || FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) @@ -3082,7 +3081,7 @@ Sema::SubstituteExplicitTemplateArguments( CXXRecordDecl *ThisContext = nullptr; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { ThisContext = Method->getParent(); - ThisTypeQuals = Method->getTypeQualifiers(); + ThisTypeQuals = Method->getMethodQualifiers(); } CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, @@ -4661,7 +4660,7 @@ AddImplicitObjectParameterType(ASTContext &Context, // The standard doesn't say explicitly, but we pick the appropriate kind of // reference type based on [over.match.funcs]p4. QualType ArgTy = Context.getTypeDeclType(Method->getParent()); - ArgTy = Context.getQualifiedType(ArgTy, Method->getTypeQualifiers()); + ArgTy = Context.getQualifiedType(ArgTy, Method->getMethodQualifiers()); if (Method->getRefQualifier() == RQ_RValue) ArgTy = Context.getRValueReferenceType(ArgTy); else diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 96abeed824..af56ff06ac 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1,9 +1,8 @@ //===------- SemaTemplateInstantiate.cpp - C++ Template Instantiation ------===/ // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===/ // // This file implements C++ template instantiation. @@ -26,6 +25,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; using namespace sema; @@ -66,9 +66,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, if (!Ctx) { Ctx = D->getDeclContext(); - // Add template arguments from a variable template instantiation. - if (VarTemplateSpecializationDecl *Spec = - dyn_cast<VarTemplateSpecializationDecl>(D)) { + // Add template arguments from a variable template instantiation. For a + // class-scope explicit specialization, there are no template arguments + // at this level, but there may be enclosing template arguments. + VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(D); + if (Spec && !Spec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa<VarTemplatePartialSpecializationDecl>(Spec)) @@ -111,8 +114,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, while (!Ctx->isFileContext()) { // Add template arguments from a class template instantiation. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { + ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Ctx); + if (Spec && !Spec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa<ClassTemplatePartialSpecializationDecl>(Spec)) @@ -129,9 +133,8 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // Add template arguments from a function template specialization. else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { if (!RelativeToPrimary && - (Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization && - !Function->getClassScopeSpecializationPattern())) + Function->getTemplateSpecializationKindForInstantiation() == + TSK_ExplicitSpecialization) break; if (const TemplateArgumentList *TemplateArgs @@ -2009,6 +2012,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiation->getInstantiatedFromMemberClass(), Pattern, PatternDef, TSK, Complain)) return true; + + llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() { + return Instantiation->getQualifiedNameAsString(); + }); + Pattern = PatternDef; // Record the point of instantiation. @@ -2675,11 +2683,14 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, == TSK_ExplicitSpecialization) continue; - if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || - Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) && + if (Context.getTargetInfo().getTriple().isOSWindows() && TSK == TSK_ExplicitInstantiationDeclaration) { - // In MSVC and Windows Itanium mode, explicit instantiation decl of the - // outer class doesn't affect the inner class. + // On Windows, explicit instantiation decl of the outer class doesn't + // affect the inner class. Typically extern template declarations are + // used in combination with dll import/export annotations, but those + // are not propagated from the outer class templates to inner classes. + // Therefore, do not instantiate inner classes on this platform, so + // that users don't end up with undefined symbols during linking. continue; } @@ -2887,7 +2898,7 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) { unsigned i = PV->getFunctionScopeIndex(); // This parameter might be from a freestanding function type within the // function and isn't necessarily referring to one of FD's parameters. - if (FD->getParamDecl(i) == PV) + if (i < FD->getNumParams() && FD->getParamDecl(i) == PV) return FD->getCanonicalDecl()->getParamDecl(i); } } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index fad3c065e8..653eb69326 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1,9 +1,8 @@ //===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/ // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===/ // // This file implements C++ template instantiation for declarations. @@ -24,6 +23,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -345,6 +345,51 @@ static void instantiateOMPDeclareSimdDeclAttr( Attr.getRange()); } +static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) { + // Both min and max expression are constant expressions. + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs); + if (Result.isInvalid()) + return; + Expr *MinExpr = Result.getAs<Expr>(); + + Result = S.SubstExpr(Attr.getMax(), TemplateArgs); + if (Result.isInvalid()) + return; + Expr *MaxExpr = Result.getAs<Expr>(); + + S.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr, + Attr.getSpellingListIndex()); +} + +static void instantiateDependentAMDGPUWavesPerEUAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AMDGPUWavesPerEUAttr &Attr, Decl *New) { + // Both min and max expression are constant expressions. + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs); + if (Result.isInvalid()) + return; + Expr *MinExpr = Result.getAs<Expr>(); + + Expr *MaxExpr = nullptr; + if (auto Max = Attr.getMax()) { + Result = S.SubstExpr(Max, TemplateArgs); + if (Result.isInvalid()) + return; + MaxExpr = Result.getAs<Expr>(); + } + + S.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr, + Attr.getSpellingListIndex()); +} + void Sema::InstantiateAttrsForDecl( const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -438,6 +483,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize = + dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) { + instantiateDependentAMDGPUFlatWorkGroupSizeAttr( + *this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New); + } + + if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize = + dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) { + instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs, + *AMDGPUFlatWorkGroupSize, New); + } + // Existing DLL attribute on the instantiation takes precedence. if (TmplAttr->getKind() == attr::DLLExport || TmplAttr->getKind() == attr::DLLImport) { @@ -1894,10 +1951,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Function; } -Decl * -TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, - TemplateParameterList *TemplateParams, - bool IsClassScopeSpecialization) { +Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( + CXXMethodDecl *D, TemplateParameterList *TemplateParams, + Optional<const ASTTemplateArgumentListInfo *> + ClassScopeSpecializationArgs) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function @@ -2101,7 +2158,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, IsExplicitSpecialization = true; } else if (const ASTTemplateArgumentListInfo *Info = - D->getTemplateSpecializationArgsAsWritten()) { + ClassScopeSpecializationArgs.getValueOr( + D->getTemplateSpecializationArgsAsWritten())) { SemaRef.LookupQualifiedName(Previous, DC); TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), @@ -2116,6 +2174,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setInvalidDecl(); IsExplicitSpecialization = true; + } else if (ClassScopeSpecializationArgs) { + // Class-scope explicit specialization written without explicit template + // arguments. + SemaRef.LookupQualifiedName(Previous, DC); + if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous)) + Method->setInvalidDecl(); + + IsExplicitSpecialization = true; } else if (!FunctionTemplate || TemplateParams || isFriend) { SemaRef.LookupQualifiedName(Previous, Record); @@ -2127,9 +2193,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Previous.clear(); } - if (!IsClassScopeSpecialization) - SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, - IsExplicitSpecialization); + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, + IsExplicitSpecialization); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); @@ -2152,6 +2217,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isDeletedAsWritten()) SemaRef.SetDeclDeleted(Method, Method->getLocation()); + // If this is an explicit specialization, mark the implicitly-instantiated + // template specialization as being an explicit specialization too. + // FIXME: Is this necessary? + if (IsExplicitSpecialization && !isFriend) + SemaRef.CompleteMemberSpecialization(Method, Previous); + // If there's a function template, let our caller handle it. if (FunctionTemplate) { // do nothing @@ -2172,10 +2243,24 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // Otherwise, add the declaration. We don't need to do this for // class-scope specializations because we'll have matched them with // the appropriate template. - } else if (!IsClassScopeSpecialization) { + } else { Owner->addDecl(Method); } + // PR17480: Honor the used attribute to instantiate member function + // definitions + if (Method->hasAttr<UsedAttr>()) { + if (const auto *A = dyn_cast<CXXRecordDecl>(Owner)) { + SourceLocation Loc; + if (const MemberSpecializationInfo *MSInfo = + A->getMemberSpecializationInfo()) + Loc = MSInfo->getPointOfInstantiation(); + else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(A)) + Loc = Spec->getPointOfInstantiation(); + SemaRef.MarkFunctionReferenced(Loc, Method); + } + } + return Method; } @@ -2768,38 +2853,8 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *Decl) { CXXMethodDecl *OldFD = Decl->getSpecialization(); - CXXMethodDecl *NewFD = - cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true)); - if (!NewFD) - return nullptr; - - TemplateArgumentListInfo ExplicitTemplateArgs; - TemplateArgumentListInfo *ExplicitTemplateArgsPtr = nullptr; - if (Decl->hasExplicitTemplateArgs()) { - if (SemaRef.Subst(Decl->templateArgs().getArgumentArray(), - Decl->templateArgs().size(), ExplicitTemplateArgs, - TemplateArgs)) - return nullptr; - ExplicitTemplateArgsPtr = &ExplicitTemplateArgs; - } - - LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, - Sema::ForExternalRedeclaration); - SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext); - if (SemaRef.CheckFunctionTemplateSpecialization( - NewFD, ExplicitTemplateArgsPtr, Previous)) { - NewFD->setInvalidDecl(); - return NewFD; - } - - // Associate the specialization with the pattern. - FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl()); - assert(Specialization && "Class scope Specialization is null"); - SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); - - // FIXME: If this is a definition, check for redefinition errors! - - return NewFD; + return cast_or_null<CXXMethodDecl>( + VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten())); } Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( @@ -2820,6 +2875,32 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( return TD; } +Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) { + SmallVector<Expr *, 5> Vars; + for (auto *I : D->varlists()) { + Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get(); + assert(isa<DeclRefExpr>(Var) && "allocate arg is not a DeclRefExpr"); + Vars.push_back(Var); + } + SmallVector<OMPClause *, 4> Clauses; + // Copy map clauses from the original mapper. + for (OMPClause *C : D->clauselists()) { + auto *AC = cast<OMPAllocatorClause>(C); + ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs); + if (!NewE.isUsable()) + continue; + OMPClause *IC = SemaRef.ActOnOpenMPAllocatorClause( + NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc()); + Clauses.push_back(IC); + } + + Sema::DeclGroupPtrTy Res = SemaRef.ActOnOpenMPAllocateDirective( + D->getLocation(), Vars, Clauses, Owner); + if (Res.get().isNull()) + return nullptr; + return Res.get().getSingleDecl(); +} + Decl *TemplateDeclInstantiator::VisitOMPRequiresDecl(OMPRequiresDecl *D) { llvm_unreachable( "Requires directive cannot be instantiated within a dependent context"); @@ -2925,6 +3006,95 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( return NewDRD; } +Decl * +TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { + // Instantiate type and check if it is allowed. + const bool RequiresInstantiation = + D->getType()->isDependentType() || + D->getType()->isInstantiationDependentType() || + D->getType()->containsUnexpandedParameterPack(); + QualType SubstMapperTy; + DeclarationName VN = D->getVarName(); + if (RequiresInstantiation) { + SubstMapperTy = SemaRef.ActOnOpenMPDeclareMapperType( + D->getLocation(), + ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs, + D->getLocation(), VN))); + } else { + SubstMapperTy = D->getType(); + } + if (SubstMapperTy.isNull()) + return nullptr; + // Create an instantiated copy of mapper. + auto *PrevDeclInScope = D->getPrevDeclInScope(); + if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) { + PrevDeclInScope = cast<OMPDeclareMapperDecl>( + SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope) + ->get<Decl *>()); + } + OMPDeclareMapperDecl *NewDMD = SemaRef.ActOnOpenMPDeclareMapperDirectiveStart( + /*S=*/nullptr, Owner, D->getDeclName(), SubstMapperTy, D->getLocation(), + VN, D->getAccess(), PrevDeclInScope); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDMD); + SmallVector<OMPClause *, 6> Clauses; + bool IsCorrect = true; + if (!RequiresInstantiation) { + // Copy the mapper variable. + NewDMD->setMapperVarRef(D->getMapperVarRef()); + // Copy map clauses from the original mapper. + for (OMPClause *C : D->clauselists()) + Clauses.push_back(C); + } else { + // Instantiate the mapper variable. + DeclarationNameInfo DirName; + SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr, + (*D->clauselist_begin())->getBeginLoc()); + SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl( + NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + cast<DeclRefExpr>(D->getMapperVarRef())->getDecl(), + cast<DeclRefExpr>(NewDMD->getMapperVarRef())->getDecl()); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(), + ThisContext); + // Instantiate map clauses. + for (OMPClause *C : D->clauselists()) { + auto *OldC = cast<OMPMapClause>(C); + SmallVector<Expr *, 4> NewVars; + for (Expr *OE : OldC->varlists()) { + Expr *NE = SemaRef.SubstExpr(OE, TemplateArgs).get(); + if (!NE) { + IsCorrect = false; + break; + } + NewVars.push_back(NE); + } + if (!IsCorrect) + break; + NestedNameSpecifierLoc NewQualifierLoc = + SemaRef.SubstNestedNameSpecifierLoc(OldC->getMapperQualifierLoc(), + TemplateArgs); + CXXScopeSpec SS; + SS.Adopt(NewQualifierLoc); + DeclarationNameInfo NewNameInfo = SemaRef.SubstDeclarationNameInfo( + OldC->getMapperIdInfo(), TemplateArgs); + OMPVarListLocTy Locs(OldC->getBeginLoc(), OldC->getLParenLoc(), + OldC->getEndLoc()); + OMPClause *NewC = SemaRef.ActOnOpenMPMapClause( + OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(), SS, + NewNameInfo, OldC->getMapType(), OldC->isImplicitMapType(), + OldC->getMapLoc(), OldC->getColonLoc(), NewVars, Locs); + Clauses.push_back(NewC); + } + SemaRef.EndOpenMPDSABlock(nullptr); + } + (void)SemaRef.ActOnOpenMPDeclareMapperDirectiveEnd(NewDMD, /*S=*/nullptr, + Clauses); + if (!IsCorrect) + return nullptr; + return NewDMD; +} + Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl( OMPCapturedExprDecl * /*D*/) { llvm_unreachable("Should not be met in templates"); @@ -2962,13 +3132,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( "for a member class template"); // Lookup the already-instantiated declaration in the instantiation - // of the class template. FIXME: Diagnose or assert if this fails? - DeclContext::lookup_result Found - = Owner->lookup(ClassTemplate->getDeclName()); - if (Found.empty()) - return nullptr; - ClassTemplateDecl *InstClassTemplate - = dyn_cast<ClassTemplateDecl>(Found.front()); + // of the class template. + ClassTemplateDecl *InstClassTemplate = + cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl( + D->getLocation(), ClassTemplate, TemplateArgs)); if (!InstClassTemplate) return nullptr; @@ -3077,6 +3244,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Instantiate the members of the class-scope explicit specialization eagerly. // We don't have support for lazy instantiation of an explicit specialization // yet, and MSVC eagerly instantiates in this case. + // FIXME: This is wrong in standard C++. if (D->isThisDeclarationADefinition() && SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs, TSK_ImplicitInstantiation, @@ -3094,6 +3262,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( assert(VarTemplate && "A template specialization without specialized template?"); + VarTemplateDecl *InstVarTemplate = + cast_or_null<VarTemplateDecl>(SemaRef.FindInstantiatedDecl( + D->getLocation(), VarTemplate, TemplateArgs)); + if (!InstVarTemplate) + return nullptr; + // Substitute the current template arguments. const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo(); VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc()); @@ -3105,28 +3279,33 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList( - VarTemplate, VarTemplate->getBeginLoc(), - const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false, - Converted)) + if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), + VarTemplateArgsInfo, false, Converted)) return nullptr; - // Find the variable template specialization declaration that - // corresponds to these arguments. + // Check whether we've already seen a declaration of this specialization. void *InsertPos = nullptr; - if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization( - Converted, InsertPos)) - // If we already have a variable template specialization, return it. - return VarSpec; + VarTemplateSpecializationDecl *PrevDecl = + InstVarTemplate->findSpecialization(Converted, InsertPos); + + // Check whether we've already seen a conflicting instantiation of this + // declaration (for instance, if there was a prior implicit instantiation). + bool Ignored; + if (PrevDecl && SemaRef.CheckSpecializationInstantiationRedecl( + D->getLocation(), D->getSpecializationKind(), PrevDecl, + PrevDecl->getSpecializationKind(), + PrevDecl->getPointOfInstantiation(), Ignored)) + return nullptr; - return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos, - VarTemplateArgsInfo, Converted); + return VisitVarTemplateSpecializationDecl( + InstVarTemplate, D, InsertPos, VarTemplateArgsInfo, Converted, PrevDecl); } Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, const TemplateArgumentListInfo &TemplateArgsInfo, - ArrayRef<TemplateArgument> Converted) { + ArrayRef<TemplateArgument> Converted, + VarTemplateSpecializationDecl *PrevDecl) { // Do substitution on the type of the declaration TypeSourceInfo *DI = @@ -3153,8 +3332,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( if (SubstQualifier(D, Var)) return nullptr; - SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, - Owner, StartingScope); + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner, + StartingScope, false, PrevDecl); return Var; } @@ -3506,7 +3685,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, Qualifiers ThisTypeQuals; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { ThisContext = cast<CXXRecordDecl>(Owner); - ThisTypeQuals = Method->getTypeQualifiers(); + ThisTypeQuals = Method->getMethodQualifiers(); } TypeSourceInfo *NewTInfo @@ -3633,25 +3812,25 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, Scope.MakeInstantiatedLocalArgPack(PatternParam); Optional<unsigned> NumArgumentsInExpansion = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); - assert(NumArgumentsInExpansion && - "should only be called when all template arguments are known"); - QualType PatternType = - PatternParam->getType()->castAs<PackExpansionType>()->getPattern(); - for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) { - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - FunctionParam->setDeclName(PatternParam->getDeclName()); - if (!PatternDecl->getType()->isDependentType()) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); - QualType T = S.SubstType(PatternType, TemplateArgs, - FunctionParam->getLocation(), - FunctionParam->getDeclName()); - if (T.isNull()) - return true; - FunctionParam->setType(T); - } + if (NumArgumentsInExpansion) { + QualType PatternType = + PatternParam->getType()->castAs<PackExpansionType>()->getPattern(); + for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) { + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + if (!PatternDecl->getType()->isDependentType()) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); + QualType T = S.SubstType(PatternType, TemplateArgs, + FunctionParam->getLocation(), + FunctionParam->getDeclName()); + if (T.isNull()) + return true; + FunctionParam->setType(T); + } - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; + } } } @@ -3882,9 +4061,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Never instantiate an explicit specialization except if it is a class scope // explicit specialization. - TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind(); - if (TSK == TSK_ExplicitSpecialization && - !Function->getClassScopeSpecializationPattern()) + TemplateSpecializationKind TSK = + Function->getTemplateSpecializationKindForInstantiation(); + if (TSK == TSK_ExplicitSpecialization) return; // Find the function body that we'll be substituting. @@ -3939,6 +4118,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, return; } + llvm::TimeTraceScope TimeScope("InstantiateFunction", [&]() { + return Function->getQualifiedNameAsString(); + }); + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. @@ -4165,7 +4348,19 @@ void Sema::BuildVariableInstantiation( const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, - bool InstantiatingVarTemplate) { + bool InstantiatingVarTemplate, + VarTemplateSpecializationDecl *PrevDeclForVarTemplateSpecialization) { + // Instantiating a partial specialization to produce a partial + // specialization. + bool InstantiatingVarTemplatePartialSpec = + isa<VarTemplatePartialSpecializationDecl>(OldVar) && + isa<VarTemplatePartialSpecializationDecl>(NewVar); + // Instantiating from a variable template (or partial specialization) to + // produce a variable template specialization. + bool InstantiatingSpecFromTemplate = + isa<VarTemplateSpecializationDecl>(NewVar) && + (OldVar->getDescribedVarTemplate() || + isa<VarTemplatePartialSpecializationDecl>(OldVar)); // If we are instantiating a local extern declaration, the // instantiation belongs lexically to the containing function. @@ -4211,8 +4406,11 @@ void Sema::BuildVariableInstantiation( NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs)) Previous.addDecl(NewPrev); } else if (!isa<VarTemplateSpecializationDecl>(NewVar) && - OldVar->hasLinkage()) + OldVar->hasLinkage()) { LookupQualifiedName(Previous, NewVar->getDeclContext(), false); + } else if (PrevDeclForVarTemplateSpecialization) { + Previous.addDecl(PrevDeclForVarTemplateSpecialization); + } CheckVariableDeclaration(NewVar, Previous); if (!InstantiatingVarTemplate) { @@ -4228,23 +4426,44 @@ void Sema::BuildVariableInstantiation( // Link instantiations of static data members back to the template from // which they were instantiated. - if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate) + // + // Don't do this when instantiating a template (we link the template itself + // back in that case) nor when instantiating a static data member template + // (that's not a member specialization). + if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate && + !InstantiatingSpecFromTemplate) NewVar->setInstantiationOfStaticDataMember(OldVar, TSK_ImplicitInstantiation); + // If the pattern is an (in-class) explicit specialization, then the result + // is also an explicit specialization. + if (VarTemplateSpecializationDecl *OldVTSD = + dyn_cast<VarTemplateSpecializationDecl>(OldVar)) { + if (OldVTSD->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(OldVTSD)) + cast<VarTemplateSpecializationDecl>(NewVar)->setSpecializationKind( + TSK_ExplicitSpecialization); + } + // Forward the mangling number from the template to the instantiated decl. Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar)); Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); - // Delay instantiation of the initializer for variable templates or inline - // static data members until a definition of the variable is needed. We need - // it right away if the type contains 'auto'. - if ((!isa<VarTemplateSpecializationDecl>(NewVar) && - !InstantiatingVarTemplate && - !(OldVar->isInline() && OldVar->isThisDeclarationADefinition() && - !NewVar->isThisDeclarationADefinition())) || - NewVar->getType()->isUndeducedType()) + // Figure out whether to eagerly instantiate the initializer. + if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) { + // We're producing a template. Don't instantiate the initializer yet. + } else if (NewVar->getType()->isUndeducedType()) { + // We need the type to complete the declaration of the variable. + InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + } else if (InstantiatingSpecFromTemplate || + (OldVar->isInline() && OldVar->isThisDeclarationADefinition() && + !NewVar->isThisDeclarationADefinition())) { + // Delay instantiation of the initializer for variable template + // specializations or inline static data members until a definition of the + // variable is needed. + } else { InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + } // Diagnose unused local variables with dependent types, where the diagnostic // will have been deferred. @@ -4344,15 +4563,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (Var->isInvalidDecl()) return; - VarTemplateSpecializationDecl *VarSpec = - dyn_cast<VarTemplateSpecializationDecl>(Var); - VarDecl *PatternDecl = nullptr, *Def = nullptr; + // Never instantiate an explicitly-specialized entity. + TemplateSpecializationKind TSK = + Var->getTemplateSpecializationKindForInstantiation(); + if (TSK == TSK_ExplicitSpecialization) + return; + + // Find the pattern and the arguments to substitute into it. + VarDecl *PatternDecl = Var->getTemplateInstantiationPattern(); + assert(PatternDecl && "no pattern for templated variable"); MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Var); + VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(Var); if (VarSpec) { // If this is a variable template specialization, make sure that it is - // non-dependent, then find its instantiation pattern. + // non-dependent. bool InstantiationDependent = false; assert(!TemplateSpecializationType::anyDependentTemplateArguments( VarSpec->getTemplateArgsInfo(), InstantiationDependent) && @@ -4360,37 +4587,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, "not type-dependent"); (void)InstantiationDependent; - // Find the variable initialization that we'll be substituting. If the - // pattern was instantiated from a member template, look back further to - // find the real pattern. - assert(VarSpec->getSpecializedTemplate() && - "Specialization without specialized template?"); - llvm::PointerUnion<VarTemplateDecl *, - VarTemplatePartialSpecializationDecl *> PatternPtr = - VarSpec->getSpecializedTemplateOrPartial(); - if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) { - VarTemplatePartialSpecializationDecl *Tmpl = - PatternPtr.get<VarTemplatePartialSpecializationDecl *>(); - while (VarTemplatePartialSpecializationDecl *From = - Tmpl->getInstantiatedFromMember()) { - if (Tmpl->isMemberSpecialization()) - break; - - Tmpl = From; - } - PatternDecl = Tmpl; - } else { - VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>(); - while (VarTemplateDecl *From = - Tmpl->getInstantiatedFromMemberTemplate()) { - if (Tmpl->isMemberSpecialization()) - break; - - Tmpl = From; - } - PatternDecl = Tmpl->getTemplatedDecl(); - } - // If this is a static data member template, there might be an // uninstantiated initializer on the declaration. If so, instantiate // it now. @@ -4434,20 +4630,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, Local.Exit(); GlobalInstantiations.perform(); } - - // Find actual definition - Def = PatternDecl->getDefinition(getASTContext()); } else { - // If this is a static data member, find its out-of-line definition. - assert(Var->isStaticDataMember() && "not a static data member?"); - PatternDecl = Var->getInstantiatedFromStaticDataMember(); - - assert(PatternDecl && "data member was not instantiated from a template?"); - assert(PatternDecl->isStaticDataMember() && "not a static data member?"); - Def = PatternDecl->getDefinition(); + assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() && + "not a static data member?"); } - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + VarDecl *Def = PatternDecl->getDefinition(getASTContext()); // If we don't have a definition of the variable template, we won't perform // any instantiation. Rather, we rely on the user to instantiate this @@ -4469,7 +4657,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, } return; } - } // FIXME: We need to track the instantiation stack in order to know which @@ -4481,11 +4668,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, /*Complain*/DefinitionRequired)) return; - - // Never instantiate an explicit specialization. - if (TSK == TSK_ExplicitSpecialization) - return; - // C++11 [temp.explicit]p10: // Except for inline functions, const variables of literal types, variables // of reference types, [...] explicit instantiation declarations @@ -5006,7 +5188,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) || ((ParentDC->isFunctionOrMethod() || - isa<OMPDeclareReductionDecl>(ParentDC)) && + isa<OMPDeclareReductionDecl>(ParentDC) || + isa<OMPDeclareMapperDecl>(ParentDC)) && ParentDC->isDependentContext()) || (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) { // D is a local of some kind. Look into the map of local @@ -5320,7 +5503,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Check if the most recent declaration has changed the specialization kind // and removed the need for implicit instantiation. - switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) { + switch (Var->getMostRecentDecl() + ->getTemplateSpecializationKindForInstantiation()) { case TSK_Undeclared: llvm_unreachable("Cannot instantitiate an undeclared specialization."); case TSK_ExplicitInstantiationDeclaration: diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 0e7fc20d24..d06b7d49b4 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -1,9 +1,8 @@ //===------- SemaTemplateVariadic.cpp - C++ Variadic Templates ------------===/ // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===/ // // This file implements semantic analysis for C++0x variadic templates. @@ -925,12 +924,16 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { namespace { // Callback to only accept typo corrections that refer to parameter packs. -class ParameterPackValidatorCCC : public CorrectionCandidateCallback { +class ParameterPackValidatorCCC final : public CorrectionCandidateCallback { public: bool ValidateCandidate(const TypoCorrection &candidate) override { NamedDecl *ND = candidate.getCorrectionDecl(); return ND && ND->isParameterPack(); } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<ParameterPackValidatorCCC>(*this); + } }; } @@ -966,18 +969,18 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, break; case LookupResult::NotFound: - case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::NotFoundInCurrentInstantiation: { + ParameterPackValidatorCCC CCC{}; if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr, - llvm::make_unique<ParameterPackValidatorCCC>(), - CTK_ErrorRecovery)) { + CCC, CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name, PDiag(diag::note_parameter_pack_here)); ParameterPack = Corrected.getCorrectionDecl(); } break; - + } case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: break; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index b4c075e9c4..299db7b2ed 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1,9 +1,8 @@ //===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -256,13 +255,27 @@ namespace { return T; } + /// Completely replace the \c auto in \p TypeWithAuto by + /// \p Replacement. Also replace \p TypeWithAuto in \c TypeAttrPair if + /// necessary. + QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement) { + QualType T = sema.ReplaceAutoType(TypeWithAuto, Replacement); + if (auto *AttrTy = TypeWithAuto->getAs<AttributedType>()) { + // Attributed type still should be an attributed type after replacement. + auto *NewAttrTy = cast<AttributedType>(T.getTypePtr()); + for (TypeAttrPair &A : AttrsForTypes) { + if (A.first == AttrTy) + A.first = NewAttrTy; + } + AttrsForTypesSorted = false; + } + return T; + } + /// Extract and remove the Attr* for a given attributed type. const Attr *takeAttrForAttributedType(const AttributedType *AT) { if (!AttrsForTypesSorted) { - std::stable_sort(AttrsForTypes.begin(), AttrsForTypes.end(), - [](const TypeAttrPair &A, const TypeAttrPair &B) { - return A.first < B.first; - }); + llvm::stable_sort(AttrsForTypes, llvm::less_first()); AttrsForTypesSorted = true; } @@ -518,8 +531,8 @@ static void distributeObjCPointerTypeAttrFromDeclarator( // attribute from being applied multiple times and gives // the source-location-filler something to work with. state.saveDeclSpecAttrs(); - moveAttrFromListToList(attr, declarator.getAttributes(), - declarator.getMutableDeclSpec().getAttributes()); + declarator.getMutableDeclSpec().getAttributes().takeOneFrom( + declarator.getAttributes(), &attr); return; } } @@ -1434,7 +1447,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; } case DeclSpec::TST_int128: - if (!S.Context.getTargetInfo().hasInt128Type()) + if (!S.Context.getTargetInfo().hasInt128Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__int128"; if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) @@ -1442,7 +1456,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { else Result = Context.Int128Ty; break; - case DeclSpec::TST_float16: Result = Context.Float16Ty; break; + case DeclSpec::TST_float16: + // CUDA host and device may have different _Float16 support, therefore + // do not diagnose _Float16 usage to avoid false alarm. + // ToDo: more precise diagnostics for CUDA. + if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "_Float16"; + Result = Context.Float16Ty; + break; case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: @@ -1452,7 +1475,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.DoubleTy; break; case DeclSpec::TST_float128: - if (!S.Context.getTargetInfo().hasFloat128Type()) + if (!S.Context.getTargetInfo().hasFloat128Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__float128"; Result = Context.Float128Ty; @@ -1868,7 +1892,7 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type, } static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){ - std::string Quals = FnTy->getTypeQuals().getAsString(); + std::string Quals = FnTy->getMethodQuals().getAsString(); switch (FnTy->getRefQualifier()) { case RQ_None: @@ -1910,7 +1934,7 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, QualifiedFunctionKind QFK) { // Does T refer to a function type with a cv-qualifier or a ref-qualifier? const FunctionProtoType *FPT = T->getAs<FunctionProtoType>(); - if (!FPT || (FPT->getTypeQuals().empty() && FPT->getRefQualifier() == RQ_None)) + if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) return false; S.Diag(Loc, diag::err_compound_qualified_function_type) @@ -2243,15 +2267,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) { - if (getLangOpts().CUDA) { - // CUDA device code doesn't support VLAs. - CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget(); - } else if (!getLangOpts().OpenMP || - shouldDiagnoseTargetSupportFromOpenMP()) { - // Some targets don't support VLAs. - Diag(Loc, diag::err_vla_unsupported); - return QualType(); - } + // CUDA device code and some other targets don't support VLAs. + targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) + ? diag::err_cuda_vla + : diag::err_vla_unsupported) + << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice) + ? CurrentCUDATarget() + : CFT_InvalidTarget); } // If this is not C99, extwarn about VLA's and C99 array size modifiers. @@ -2913,7 +2935,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda(); assert(LSI && "No LambdaScopeInfo on the stack!"); const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth; - const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size(); + const unsigned AutoParameterPosition = LSI->TemplateParams.size(); const bool IsParameterPack = D.hasEllipsis(); // Create the TemplateTypeParmDecl here to retrieve the corresponding @@ -2925,12 +2947,13 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), TemplateParameterDepth, AutoParameterPosition, /*Identifier*/ nullptr, false, IsParameterPack); - LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam); + CorrespondingTemplateParam->setImplicit(); + LSI->TemplateParams.push_back(CorrespondingTemplateParam); // Replace the 'auto' in the function parameter with this invented // template type parameter. // FIXME: Retain some type sugar to indicate that this was written // as 'auto'. - T = SemaRef.ReplaceAutoType( + T = state.ReplaceAutoType( T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0)); } break; @@ -3916,6 +3939,25 @@ static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr, llvm_unreachable("unknown NullabilityKind"); } +// Diagnose whether this is a case with the multiple addr spaces. +// Returns true if this is an invalid case. +// ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified +// by qualifiers for two or more different address spaces." +static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld, + LangAS ASNew, + SourceLocation AttrLoc) { + if (ASOld != LangAS::Default) { + if (ASOld != ASNew) { + S.Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); + return true; + } + // Emit a warning if they are identical; it's likely unintended. + S.Diag(AttrLoc, + diag::warn_attribute_address_multiple_identical_qualifiers); + } + return false; +} + static TypeSourceInfo * GetTypeSourceInfoForDeclarator(TypeProcessingState &State, QualType T, TypeSourceInfo *ReturnTypeInfo); @@ -3944,7 +3986,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Does T refer to a function type with a cv-qualifier or a ref-qualifier? bool IsQualifiedFunction = T->isFunctionProtoType() && - (!T->castAs<FunctionProtoType>()->getTypeQuals().empty() || + (!T->castAs<FunctionProtoType>()->getMethodQuals().empty() || T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None); // If T is 'decltype(auto)', the only declarators we can have are parens @@ -4194,7 +4236,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, auto inferPointerNullability = [&](SimplePointerKind pointerKind, SourceLocation pointerLoc, SourceLocation pointerEndLoc, - ParsedAttributesView &attrs) -> ParsedAttr * { + ParsedAttributesView &attrs, AttributePool &Pool) -> ParsedAttr * { // We've seen a pointer. if (NumPointersRemaining > 0) --NumPointersRemaining; @@ -4208,11 +4250,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ParsedAttr::Syntax syntax = inferNullabilityCS ? ParsedAttr::AS_ContextSensitiveKeyword : ParsedAttr::AS_Keyword; - ParsedAttr *nullabilityAttr = - state.getDeclarator().getAttributePool().create( - S.getNullabilityKeyword(*inferNullability), - SourceRange(pointerLoc), nullptr, SourceLocation(), nullptr, 0, - syntax); + ParsedAttr *nullabilityAttr = Pool.create( + S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc), + nullptr, SourceLocation(), nullptr, 0, syntax); attrs.addAtEnd(nullabilityAttr); @@ -4271,7 +4311,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (auto *attr = inferPointerNullability( pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), D.getDeclSpec().getEndLoc(), - D.getMutableDeclSpec().getAttributes())) { + D.getMutableDeclSpec().getAttributes(), + D.getMutableDeclSpec().getAttributePool())) { T = state.getAttributedType( createNullabilityAttr(Context, *attr, *inferNullability), T, T); } @@ -4311,7 +4352,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability. inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc, - DeclType.EndLoc, DeclType.getAttrs()); + DeclType.EndLoc, DeclType.getAttrs(), + state.getDeclarator().getAttributePool()); T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) { @@ -4333,7 +4375,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc, - DeclType.EndLoc, DeclType.getAttrs()); + DeclType.EndLoc, DeclType.getAttrs(), + state.getDeclarator().getAttributePool()); if (LangOpts.ObjC && T->getAs<ObjCObjectType>()) { T = Context.getObjCObjectPointerType(T); @@ -4558,7 +4601,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (FTI.isVariadic && !(D.getIdentifier() && ((D.getIdentifier()->getName() == "printf" && - LangOpts.OpenCLVersion >= 120) || + (LangOpts.OpenCLCPlusPlus || LangOpts.OpenCLVersion >= 120)) || D.getIdentifier()->getName().startswith("__")))) { S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function); D.setInvalidType(true); @@ -4823,18 +4866,35 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, Exceptions, EPI.ExceptionSpec); - const auto &Spec = D.getCXXScopeSpec(); + // FIXME: Set address space from attrs for C++ mode here. // OpenCLCPlusPlus: A class member function has an address space. - if (state.getSema().getLangOpts().OpenCLCPlusPlus && - ((!Spec.isEmpty() && - Spec.getScopeRep()->getKind() == NestedNameSpecifier::TypeSpec) || - state.getDeclarator().getContext() == - DeclaratorContext::MemberContext)) { - LangAS CurAS = EPI.TypeQuals.getAddressSpace(); + auto IsClassMember = [&]() { + return (!state.getDeclarator().getCXXScopeSpec().isEmpty() && + state.getDeclarator() + .getCXXScopeSpec() + .getScopeRep() + ->getKind() == NestedNameSpecifier::TypeSpec) || + state.getDeclarator().getContext() == + DeclaratorContext::MemberContext; + }; + + if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) { + LangAS ASIdx = LangAS::Default; + // Take address space attr if any and mark as invalid to avoid adding + // them later while creating QualType. + if (FTI.MethodQualifiers) + for (ParsedAttr &attr : FTI.MethodQualifiers->getAttributes()) { + LangAS ASIdxNew = attr.asOpenCLLangAS(); + if (DiagnoseMultipleAddrSpaceAttributes(S, ASIdx, ASIdxNew, + attr.getLoc())) + D.setInvalidType(true); + else + ASIdx = ASIdxNew; + } // If a class member function's address space is not set, set it to // __generic. LangAS AS = - (CurAS == LangAS::Default ? LangAS::opencl_generic : CurAS); + (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx); EPI.TypeQuals.addAddressSpace(AS); } T = Context.getFunctionType(T, ParamTys, EPI); @@ -4848,7 +4908,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability. inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc, - DeclType.EndLoc, DeclType.getAttrs()); + DeclType.EndLoc, DeclType.getAttrs(), + state.getDeclarator().getAttributePool()); if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. @@ -4918,11 +4979,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, processTypeAttrs(state, T, TAL_DeclChunk, DeclType.getAttrs()); if (DeclType.Kind != DeclaratorChunk::Paren) { - if (ExpectNoDerefChunk) { - if (!IsNoDerefableChunk(DeclType)) - S.Diag(DeclType.Loc, diag::warn_noderef_on_non_pointer_or_array); - ExpectNoDerefChunk = false; - } + if (ExpectNoDerefChunk && !IsNoDerefableChunk(DeclType)) + S.Diag(DeclType.Loc, diag::warn_noderef_on_non_pointer_or_array); ExpectNoDerefChunk = state.didParseNoDeref(); } @@ -4949,7 +5007,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; case DeclaratorChunk::Function: { const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - if (FTI.NumParams == 0 && !FTI.isVariadic) + // We supress the warning when there's no LParen location, as this + // indicates the declaration was an implicit declaration, which gets + // warned about separately via -Wimplicit-function-declaration. + if (FTI.NumParams == 0 && !FTI.isVariadic && FTI.getLParenLoc().isValid()) S.Diag(DeclType.Loc, diag::warn_strict_prototypes) << IsBlock << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void"); @@ -5752,28 +5813,27 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { // Type Attribute Processing //===----------------------------------------------------------------------===// -/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression -/// is uninstantiated. If instantiated it will apply the appropriate address space -/// to the type. This function allows dependent template variables to be used in -/// conjunction with the address_space attribute -QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, - SourceLocation AttrLoc) { +/// Build an AddressSpace index from a constant expression and diagnose any +/// errors related to invalid address_spaces. Returns true on successfully +/// building an AddressSpace index. +static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx, + const Expr *AddrSpace, + SourceLocation AttrLoc) { if (!AddrSpace->isValueDependent()) { - llvm::APSInt addrSpace(32); - if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) { - Diag(AttrLoc, diag::err_attribute_argument_type) + if (!AddrSpace->isIntegerConstantExpr(addrSpace, S.Context)) { + S.Diag(AttrLoc, diag::err_attribute_argument_type) << "'address_space'" << AANT_ArgumentIntegerConstant << AddrSpace->getSourceRange(); - return QualType(); + return false; } // Bounds checking. if (addrSpace.isSigned()) { if (addrSpace.isNegative()) { - Diag(AttrLoc, diag::err_attribute_address_space_negative) + S.Diag(AttrLoc, diag::err_attribute_address_space_negative) << AddrSpace->getSourceRange(); - return QualType(); + return false; } addrSpace.setIsSigned(false); } @@ -5782,27 +5842,31 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, max = Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace; if (addrSpace > max) { - Diag(AttrLoc, diag::err_attribute_address_space_too_high) + S.Diag(AttrLoc, diag::err_attribute_address_space_too_high) << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange(); - return QualType(); + return false; } - LangAS ASIdx = + ASIdx = getLangASFromTargetAS(static_cast<unsigned>(addrSpace.getZExtValue())); + return true; + } - // If this type is already address space qualified with a different - // address space, reject it. - // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified - // by qualifiers for two or more different address spaces." - if (T.getAddressSpace() != LangAS::Default) { - if (T.getAddressSpace() != ASIdx) { - Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); - return QualType(); - } else - // Emit a warning if they are identical; it's likely unintended. - Diag(AttrLoc, - diag::warn_attribute_address_multiple_identical_qualifiers); - } + // Default value for DependentAddressSpaceTypes + ASIdx = LangAS::Default; + return true; +} + +/// BuildAddressSpaceAttr - Builds a DependentAddressSpaceType if an expression +/// is uninstantiated. If instantiated it will apply the appropriate address +/// space to the type. This function allows dependent template variables to be +/// used in conjunction with the address_space attribute +QualType Sema::BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, + SourceLocation AttrLoc) { + if (!AddrSpace->isValueDependent()) { + if (DiagnoseMultipleAddrSpaceAttributes(*this, T.getAddressSpace(), ASIdx, + AttrLoc)) + return QualType(); return Context.getAddrSpaceQualType(T, ASIdx); } @@ -5820,6 +5884,14 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, return Context.getDependentAddressSpaceType(T, AddrSpace, AttrLoc); } +QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, + SourceLocation AttrLoc) { + LangAS ASIdx; + if (!BuildAddressSpaceIndex(*this, ASIdx, AddrSpace, AttrLoc)) + return QualType(); + return BuildAddressSpaceAttr(T, ASIdx, AddrSpace, AttrLoc); +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -5856,7 +5928,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); ExprResult AddrSpace = S.ActOnIdExpression( - S.getCurScope(), SS, TemplateKWLoc, id, false, false); + S.getCurScope(), SS, TemplateKWLoc, id, /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); if (AddrSpace.isInvalid()) return; @@ -5865,49 +5938,51 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); } - // Create the DependentAddressSpaceType or append an address space onto - // the type. - QualType T = S.BuildAddressSpaceAttr(Type, ASArgExpr, Attr.getLoc()); + LangAS ASIdx; + if (!BuildAddressSpaceIndex(S, ASIdx, ASArgExpr, Attr.getLoc())) { + Attr.setInvalid(); + return; + } - if (!T.isNull()) { - ASTContext &Ctx = S.Context; - auto *ASAttr = ::new (Ctx) AddressSpaceAttr( - Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), - static_cast<unsigned>(T.getQualifiers().getAddressSpace())); - Type = State.getAttributedType(ASAttr, T, T); + ASTContext &Ctx = S.Context; + auto *ASAttr = ::new (Ctx) AddressSpaceAttr( + Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), + static_cast<unsigned>(ASIdx)); + + // If the expression is not value dependent (not templated), then we can + // apply the address space qualifiers just to the equivalent type. + // Otherwise, we make an AttributedType with the modified and equivalent + // type the same, and wrap it in a DependentAddressSpaceType. When this + // dependent type is resolved, the qualifier is added to the equivalent type + // later. + QualType T; + if (!ASArgExpr->isValueDependent()) { + QualType EquivType = + S.BuildAddressSpaceAttr(Type, ASIdx, ASArgExpr, Attr.getLoc()); + if (EquivType.isNull()) { + Attr.setInvalid(); + return; + } + T = State.getAttributedType(ASAttr, Type, EquivType); } else { - Attr.setInvalid(); + T = State.getAttributedType(ASAttr, Type, Type); + T = S.BuildAddressSpaceAttr(T, ASIdx, ASArgExpr, Attr.getLoc()); } + + if (!T.isNull()) + Type = T; + else + Attr.setInvalid(); } else { // The keyword-based type attributes imply which address space to use. - switch (Attr.getKind()) { - case ParsedAttr::AT_OpenCLGlobalAddressSpace: - ASIdx = LangAS::opencl_global; break; - case ParsedAttr::AT_OpenCLLocalAddressSpace: - ASIdx = LangAS::opencl_local; break; - case ParsedAttr::AT_OpenCLConstantAddressSpace: - ASIdx = LangAS::opencl_constant; break; - case ParsedAttr::AT_OpenCLGenericAddressSpace: - ASIdx = LangAS::opencl_generic; break; - case ParsedAttr::AT_OpenCLPrivateAddressSpace: - ASIdx = LangAS::opencl_private; break; - default: + ASIdx = Attr.asOpenCLLangAS(); + if (ASIdx == LangAS::Default) llvm_unreachable("Invalid address space"); - } - // If this type is already address space qualified with a different - // address space, reject it. - // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by - // qualifiers for two or more different address spaces." - if (Type.getAddressSpace() != LangAS::Default) { - if (Type.getAddressSpace() != ASIdx) { - S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); - Attr.setInvalid(); - return; - } else - // Emit a warning if they are identical; it's likely unintended. - S.Diag(Attr.getLoc(), - diag::warn_attribute_address_multiple_identical_qualifiers); + if (DiagnoseMultipleAddrSpaceAttributes(S, Type.getAddressSpace(), ASIdx, + Attr.getLoc())) { + Attr.setInvalid(); + return; } Type = S.Context.getAddrSpaceQualType(Type, ASIdx); @@ -6871,19 +6946,16 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, if (!supportsVariadicCall(CC)) { const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn); if (FnP && FnP->isVariadic()) { - unsigned DiagID = diag::err_cconv_varargs; - // stdcall and fastcall are ignored with a warning for GCC and MS // compatibility. - bool IsInvalid = true; - if (CC == CC_X86StdCall || CC == CC_X86FastCall) { - DiagID = diag::warn_cconv_varargs; - IsInvalid = false; - } + if (CC == CC_X86StdCall || CC == CC_X86FastCall) + return S.Diag(attr.getLoc(), diag::warn_cconv_ignored) + << FunctionType::getNameForCallConv(CC) + << (int)Sema::CallingConventionIgnoredReason::VariadicFunction; - S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC); - if (IsInvalid) attr.setInvalid(); - return true; + attr.setInvalid(); + return S.Diag(attr.getLoc(), diag::err_cconv_varargs) + << FunctionType::getNameForCallConv(CC); } } @@ -6938,8 +7010,9 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, // Issue a warning on ignored calling convention -- except of __stdcall. // Again, this is what MS compiler does. if (CurCC != CC_X86StdCall) - Diag(Loc, diag::warn_cconv_structors) - << FunctionType::getNameForCallConv(CurCC); + Diag(Loc, diag::warn_cconv_ignored) + << FunctionType::getNameForCallConv(CurCC) + << (int)Sema::CallingConventionIgnoredReason::ConstructorDestructor; // Default adjustment. } else { // Only adjust types with the default convention. For example, on Windows @@ -6986,7 +7059,8 @@ static void HandleVectorSizeAttr(QualType &CurType, const ParsedAttr &Attr, Id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc, - Id, false, false); + Id, /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); if (Size.isInvalid()) return; @@ -7023,7 +7097,8 @@ static void HandleExtVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc, - id, false, false); + id, /*HasTrailingLParen=*/false, + /*IsAddressOfOperand=*/false); if (Size.isInvalid()) return; @@ -7234,8 +7309,10 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, // otherwise it will fail some sema check. IsFuncReturnType || IsFuncType || // Do not deduce addr space for member types of struct, except the pointee - // type of a pointer member type. - (D.getContext() == DeclaratorContext::MemberContext && !IsPointee) || + // type of a pointer member type or static data members. + (D.getContext() == DeclaratorContext::MemberContext && + (!IsPointee && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)) || // Do not deduce addr space for types used to define a typedef and the // typedef itself, except the pointee type of a pointer type which is used // to define the typedef. @@ -7244,9 +7321,12 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, // Do not deduce addr space of the void type, e.g. in f(void), otherwise // it will fail some sema check. (T->isVoidType() && !IsPointee) || - // Do not deduce address spaces for dependent types because they might end + // Do not deduce addr spaces for dependent types because they might end // up instantiating to a type with an explicit address space qualifier. - T->isDependentType()) + T->isDependentType() || + // Do not deduce addr space of decltype because it will be taken from + // its argument. + T->isDecltypeType()) return; LangAS ImpAddr = LangAS::Default; @@ -7338,9 +7418,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (!IsTypeAttr) continue; } - } else if (TAL != TAL_DeclChunk) { + } else if (TAL != TAL_DeclChunk && + attr.getKind() != ParsedAttr::AT_AddressSpace) { // Otherwise, only consider type processing for a C++11 attribute if // it's actually been applied to a type. + // We also allow C++11 address_space attributes to pass through. continue; } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index df14768cbe..b1b2a911c2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1,9 +1,8 @@ //===------- TreeTransform.h - Semantic Tree Transformation -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file implements a semantic tree transformation that takes a given @@ -319,6 +318,13 @@ public: TypeSourceInfo *TransformTypeWithDeducedTST(TypeSourceInfo *DI); /// @} + /// The reason why the value of a statement is not discarded, if any. + enum StmtDiscardKind { + SDK_Discarded, + SDK_NotDiscarded, + SDK_StmtExprResult, + }; + /// Transform the given statement. /// /// By default, this routine transforms a statement by delegating to the @@ -328,7 +334,7 @@ public: /// other mechanism. /// /// \returns the transformed statement. - StmtResult TransformStmt(Stmt *S, bool DiscardedValue = false); + StmtResult TransformStmt(Stmt *S, StmtDiscardKind SDK = SDK_Discarded); /// Transform the given statement. /// @@ -673,6 +679,9 @@ public: #define STMT(Node, Parent) \ LLVM_ATTRIBUTE_NOINLINE \ StmtResult Transform##Node(Node *S); +#define VALUESTMT(Node, Parent) \ + LLVM_ATTRIBUTE_NOINLINE \ + StmtResult Transform##Node(Node *S, StmtDiscardKind SDK); #define EXPR(Node, Parent) \ LLVM_ATTRIBUTE_NOINLINE \ ExprResult Transform##Node(Node *E); @@ -1545,6 +1554,16 @@ public: return getSema().ActOnOpenMPSimdlenClause(Len, StartLoc, LParenLoc, EndLoc); } + /// Build a new OpenMP 'allocator' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAllocatorClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPAllocatorClause(A, StartLoc, LParenLoc, EndLoc); + } + /// Build a new OpenMP 'collapse' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -1795,17 +1814,30 @@ public: /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. - OMPClause * - RebuildOMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, - ArrayRef<SourceLocation> MapTypeModifiersLoc, - OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, - SourceLocation MapLoc, SourceLocation ColonLoc, - ArrayRef<Expr *> VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc) { + OMPClause *RebuildOMPMapClause( + ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, + ArrayRef<SourceLocation> MapTypeModifiersLoc, + CXXScopeSpec MapperIdScopeSpec, DeclarationNameInfo MapperId, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) { return getSema().ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, - MapType, IsMapTypeImplicit, MapLoc, - ColonLoc, VarList, StartLoc, - LParenLoc, EndLoc); + MapperIdScopeSpec, MapperId, MapType, + IsMapTypeImplicit, MapLoc, ColonLoc, + VarList, Locs, UnresolvedMappers); + } + + /// Build a new OpenMP 'allocate' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAllocateClause(Expr *Allocate, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPAllocateClause(Allocate, VarList, StartLoc, + LParenLoc, ColonLoc, EndLoc); } /// Build a new OpenMP 'num_teams' clause. @@ -1892,10 +1924,12 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPToClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, + const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers) { + return getSema().ActOnOpenMPToClause(VarList, MapperIdScopeSpec, MapperId, + Locs, UnresolvedMappers); } /// Build a new OpenMP 'from' clause. @@ -1903,11 +1937,12 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPFromClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, - EndLoc); + CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperId, + const OMPVarListLocTy &Locs, + ArrayRef<Expr *> UnresolvedMappers) { + return getSema().ActOnOpenMPFromClause(VarList, MapperIdScopeSpec, MapperId, + Locs, UnresolvedMappers); } /// Build a new OpenMP 'use_device_ptr' clause. @@ -1915,11 +1950,8 @@ public: /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPUseDevicePtrClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, - EndLoc); + const OMPVarListLocTy &Locs) { + return getSema().ActOnOpenMPUseDevicePtrClause(VarList, Locs); } /// Build a new OpenMP 'is_device_ptr' clause. @@ -1927,11 +1959,8 @@ public: /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPIsDevicePtrClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, - EndLoc); + const OMPVarListLocTy &Locs) { + return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs); } /// Rebuild the operand to an Objective-C \@synchronized statement. @@ -2716,7 +2745,7 @@ public: SourceRange TypeIdParens, QualType AllocatedType, TypeSourceInfo *AllocatedTypeInfo, - Expr *ArraySize, + Optional<Expr *> ArraySize, SourceRange DirectInitRange, Expr *Initializer) { return getSema().BuildCXXNew(StartLoc, UseGlobal, @@ -3270,7 +3299,7 @@ private: }; template <typename Derived> -StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, bool DiscardedValue) { +StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, StmtDiscardKind SDK) { if (!S) return S; @@ -3278,8 +3307,12 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, bool DiscardedValue) { case Stmt::NoStmtClass: break; // Transform individual statement nodes + // Pass SDK into statements that can produce a value #define STMT(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S)); +#define VALUESTMT(Node, Parent) \ + case Stmt::Node##Class: \ + return getDerived().Transform##Node(cast<Node>(S), SDK); #define ABSTRACT_STMT(Node) #define EXPR(Node, Parent) #include "clang/AST/StmtNodes.inc" @@ -3291,10 +3324,10 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S, bool DiscardedValue) { #include "clang/AST/StmtNodes.inc" { ExprResult E = getDerived().TransformExpr(cast<Expr>(S)); - if (E.isInvalid()) - return StmtError(); - return getSema().ActOnExprStmt(E, DiscardedValue); + if (SDK == SDK_StmtExprResult) + E = getSema().ActOnStmtExprResult(E); + return getSema().ActOnExprStmt(E, SDK == SDK_Discarded); } } @@ -6521,8 +6554,9 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, bool SubStmtChanged = false; SmallVector<Stmt*, 8> Statements; for (auto *B : S->body()) { - StmtResult Result = - getDerived().TransformStmt(B, !IsStmtExpr || B != S->body_back()); + StmtResult Result = getDerived().TransformStmt( + B, + IsStmtExpr && B == S->body_back() ? SDK_StmtExprResult : SDK_Discarded); if (Result.isInvalid()) { // Immediately fail if this was a DeclStmt, since it's very @@ -6585,7 +6619,8 @@ TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) { return StmtError(); // Transform the statement following the case - StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + StmtResult SubStmt = + getDerived().TransformStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); @@ -6593,11 +6628,11 @@ TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) { return getDerived().RebuildCaseStmtBody(Case.get(), SubStmt.get()); } -template<typename Derived> -StmtResult -TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) { +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) { // Transform the statement following the default case - StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + StmtResult SubStmt = + getDerived().TransformStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); @@ -6608,8 +6643,8 @@ TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) { template<typename Derived> StmtResult -TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { - StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); +TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S, StmtDiscardKind SDK) { + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK); if (SubStmt.isInvalid()) return StmtError(); @@ -6618,6 +6653,11 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { if (!LD) return StmtError(); + // If we're transforming "in-place" (we're not creating new local + // declarations), assume we're replacing the old label statement + // and clear out the reference to it. + if (LD == S->getDecl()) + S->getDecl()->setStmt(nullptr); // FIXME: Pass the real colon location in. return getDerived().RebuildLabelStmt(S->getIdentLoc(), @@ -6643,7 +6683,9 @@ const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) { } template <typename Derived> -StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { +StmtResult +TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S, + StmtDiscardKind SDK) { bool AttrsChanged = false; SmallVector<const Attr *, 1> Attrs; @@ -6654,7 +6696,7 @@ StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { Attrs.push_back(R); } - StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK); if (SubStmt.isInvalid()) return StmtError(); @@ -7359,7 +7401,8 @@ StmtResult TreeTransform<Derived>::TransformObjCForCollectionStmt( ObjCForCollectionStmt *S) { // Transform the element statement. - StmtResult Element = getDerived().TransformStmt(S->getElement()); + StmtResult Element = + getDerived().TransformStmt(S->getElement(), SDK_NotDiscarded); if (Element.isInvalid()) return StmtError(); @@ -8325,6 +8368,16 @@ TreeTransform<Derived>::TransformOMPSafelenClause(OMPSafelenClause *C) { template <typename Derived> OMPClause * +TreeTransform<Derived>::TransformOMPAllocatorClause(OMPAllocatorClause *C) { + ExprResult E = getDerived().TransformExpr(C->getAllocator()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPAllocatorClause( + E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause * TreeTransform<Derived>::TransformOMPSimdlenClause(OMPSimdlenClause *C) { ExprResult E = getDerived().TransformExpr(C->getSimdlen()); if (E.isInvalid()) @@ -8797,8 +8850,85 @@ TreeTransform<Derived>::TransformOMPDeviceClause(OMPDeviceClause *C) { C->getLParenLoc(), C->getEndLoc()); } +template <typename Derived, class T> +bool transformOMPMappableExprListClause( + TreeTransform<Derived> &TT, OMPMappableExprListClause<T> *C, + llvm::SmallVectorImpl<Expr *> &Vars, CXXScopeSpec &MapperIdScopeSpec, + DeclarationNameInfo &MapperIdInfo, + llvm::SmallVectorImpl<Expr *> &UnresolvedMappers) { + // Transform expressions in the list. + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = TT.getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return true; + Vars.push_back(EVar.get()); + } + // Transform mapper scope specifier and identifier. + NestedNameSpecifierLoc QualifierLoc; + if (C->getMapperQualifierLoc()) { + QualifierLoc = TT.getDerived().TransformNestedNameSpecifierLoc( + C->getMapperQualifierLoc()); + if (!QualifierLoc) + return true; + } + MapperIdScopeSpec.Adopt(QualifierLoc); + MapperIdInfo = C->getMapperIdInfo(); + if (MapperIdInfo.getName()) { + MapperIdInfo = TT.getDerived().TransformDeclarationNameInfo(MapperIdInfo); + if (!MapperIdInfo.getName()) + return true; + } + // Build a list of all candidate OMPDeclareMapperDecls, which is provided by + // the previous user-defined mapper lookup in dependent environment. + for (auto *E : C->mapperlists()) { + // Transform all the decls. + if (E) { + auto *ULE = cast<UnresolvedLookupExpr>(E); + UnresolvedSet<8> Decls; + for (auto *D : ULE->decls()) { + NamedDecl *InstD = + cast<NamedDecl>(TT.getDerived().TransformDecl(E->getExprLoc(), D)); + Decls.addDecl(InstD, InstD->getAccess()); + } + UnresolvedMappers.push_back(UnresolvedLookupExpr::Create( + TT.getSema().Context, /*NamingClass=*/nullptr, + MapperIdScopeSpec.getWithLocInContext(TT.getSema().Context), + MapperIdInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), + Decls.end())); + } else { + UnresolvedMappers.push_back(nullptr); + } + } + return false; +} + template <typename Derived> OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) { + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + llvm::SmallVector<Expr *, 16> Vars; + CXXScopeSpec MapperIdScopeSpec; + DeclarationNameInfo MapperIdInfo; + llvm::SmallVector<Expr *, 16> UnresolvedMappers; + if (transformOMPMappableExprListClause<Derived, OMPMapClause>( + *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) + return nullptr; + return getDerived().RebuildOMPMapClause( + C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec, + MapperIdInfo, C->getMapType(), C->isImplicitMapType(), C->getMapLoc(), + C->getColonLoc(), Vars, Locs, UnresolvedMappers); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPAllocateClause(OMPAllocateClause *C) { + Expr *Allocator = C->getAllocator(); + if (Allocator) { + ExprResult AllocatorRes = getDerived().TransformExpr(Allocator); + if (AllocatorRes.isInvalid()) + return nullptr; + Allocator = AllocatorRes.get(); + } llvm::SmallVector<Expr *, 16> Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { @@ -8807,10 +8937,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) { return nullptr; Vars.push_back(EVar.get()); } - return getDerived().RebuildOMPMapClause( - C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), C->getMapType(), - C->isImplicitMapType(), C->getMapLoc(), C->getColonLoc(), Vars, - C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + return getDerived().RebuildOMPAllocateClause( + Allocator, Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), + C->getEndLoc()); } template <typename Derived> @@ -8891,30 +9020,30 @@ TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) { template <typename Derived> OMPClause *TreeTransform<Derived>::TransformOMPToClause(OMPToClause *C) { + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); llvm::SmallVector<Expr *, 16> Vars; - Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { - ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); - if (EVar.isInvalid()) - return 0; - Vars.push_back(EVar.get()); - } - return getDerived().RebuildOMPToClause(Vars, C->getBeginLoc(), - C->getLParenLoc(), C->getEndLoc()); + CXXScopeSpec MapperIdScopeSpec; + DeclarationNameInfo MapperIdInfo; + llvm::SmallVector<Expr *, 16> UnresolvedMappers; + if (transformOMPMappableExprListClause<Derived, OMPToClause>( + *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) + return nullptr; + return getDerived().RebuildOMPToClause(Vars, MapperIdScopeSpec, MapperIdInfo, + Locs, UnresolvedMappers); } template <typename Derived> OMPClause *TreeTransform<Derived>::TransformOMPFromClause(OMPFromClause *C) { + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); llvm::SmallVector<Expr *, 16> Vars; - Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { - ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); - if (EVar.isInvalid()) - return 0; - Vars.push_back(EVar.get()); - } - return getDerived().RebuildOMPFromClause(Vars, C->getBeginLoc(), - C->getLParenLoc(), C->getEndLoc()); + CXXScopeSpec MapperIdScopeSpec; + DeclarationNameInfo MapperIdInfo; + llvm::SmallVector<Expr *, 16> UnresolvedMappers; + if (transformOMPMappableExprListClause<Derived, OMPFromClause>( + *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) + return nullptr; + return getDerived().RebuildOMPFromClause( + Vars, MapperIdScopeSpec, MapperIdInfo, Locs, UnresolvedMappers); } template <typename Derived> @@ -8928,8 +9057,8 @@ OMPClause *TreeTransform<Derived>::TransformOMPUseDevicePtrClause( return nullptr; Vars.push_back(EVar.get()); } - return getDerived().RebuildOMPUseDevicePtrClause( - Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + return getDerived().RebuildOMPUseDevicePtrClause(Vars, Locs); } template <typename Derived> @@ -8943,8 +9072,8 @@ TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { return nullptr; Vars.push_back(EVar.get()); } - return getDerived().RebuildOMPIsDevicePtrClause( - Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + return getDerived().RebuildOMPIsDevicePtrClause(Vars, Locs); } //===----------------------------------------------------------------------===// @@ -9072,10 +9201,10 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { SmallVector<Expr *, 4> AssocExprs; SmallVector<TypeSourceInfo *, 4> AssocTypes; - for (unsigned i = 0; i != E->getNumAssocs(); ++i) { - TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i); - if (TS) { - TypeSourceInfo *AssocType = getDerived().TransformType(TS); + for (const GenericSelectionExpr::Association &Assoc : E->associations()) { + TypeSourceInfo *TSI = Assoc.getTypeSourceInfo(); + if (TSI) { + TypeSourceInfo *AssocType = getDerived().TransformType(TSI); if (!AssocType) return ExprError(); AssocTypes.push_back(AssocType); @@ -9083,7 +9212,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { AssocTypes.push_back(nullptr); } - ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i)); + ExprResult AssocExpr = + getDerived().TransformExpr(Assoc.getAssociationExpr()); if (AssocExpr.isInvalid()) return ExprError(); AssocExprs.push_back(AssocExpr.get()); @@ -10248,9 +10378,16 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { return ExprError(); // Transform the size of the array we're allocating (if any). - ExprResult ArraySize = getDerived().TransformExpr(E->getArraySize()); - if (ArraySize.isInvalid()) - return ExprError(); + Optional<Expr *> ArraySize; + if (Optional<Expr *> OldArraySize = E->getArraySize()) { + ExprResult NewArraySize; + if (*OldArraySize) { + NewArraySize = getDerived().TransformExpr(*OldArraySize); + if (NewArraySize.isInvalid()) + return ExprError(); + } + ArraySize = NewArraySize.get(); + } // Transform the placement arguments (if any). bool ArgumentChanged = false; @@ -10287,7 +10424,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { if (!getDerived().AlwaysRebuild() && AllocTypeInfo == E->getAllocatedTypeSourceInfo() && - ArraySize.get() == E->getArraySize() && + ArraySize == E->getArraySize() && NewInit.get() == OldInit && OperatorNew == E->getOperatorNew() && OperatorDelete == E->getOperatorDelete() && @@ -10314,7 +10451,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { } QualType AllocType = AllocTypeInfo->getType(); - if (!ArraySize.get()) { + if (!ArraySize) { // If no array size was specified, but the new expression was // instantiated with an array type (e.g., "new T" where T is // instantiated with "int[4]"), extract the outer bound from the @@ -10342,7 +10479,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { E->getBeginLoc(), E->isGlobalNew(), /*FIXME:*/ E->getBeginLoc(), PlacementArgs, /*FIXME:*/ E->getBeginLoc(), E->getTypeIdParens(), AllocType, - AllocTypeInfo, ArraySize.get(), E->getDirectInitRange(), NewInit.get()); + AllocTypeInfo, ArraySize, E->getDirectInitRange(), NewInit.get()); } template<typename Derived> diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp index 340b7fae78..b451403544 100644 --- a/lib/Sema/TypeLocBuilder.cpp +++ b/lib/Sema/TypeLocBuilder.cpp @@ -1,9 +1,8 @@ //===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h index 536ea1c07f..1e6883926a 100644 --- a/lib/Sema/TypeLocBuilder.h +++ b/lib/Sema/TypeLocBuilder.h @@ -1,9 +1,8 @@ //===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // |