summaryrefslogtreecommitdiff
path: root/clang/lib/Sema/Sema.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/Sema.cpp')
-rw-r--r--clang/lib/Sema/Sema.cpp372
1 files changed, 263 insertions, 109 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2cd158a8b43c1..2f2b52106f3d4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "UsedDeclVisitor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -22,6 +23,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/HeaderSearch.h"
@@ -52,6 +54,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
+IdentifierInfo *
+Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
+ unsigned int Index) {
+ std::string InventedName;
+ llvm::raw_string_ostream OS(InventedName);
+
+ if (!ParamName)
+ OS << "auto:" << Index + 1;
+ else
+ OS << ParamName->getName() << ":auto";
+
+ OS.flush();
+ return &Context.Idents.get(OS.str());
+}
+
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -127,10 +144,13 @@ public:
} // end namespace sema
} // end namespace clang
+const unsigned Sema::MaxAlignmentExponent;
+const unsigned Sema::MaximumAlignment;
+
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
: ExternalSource(nullptr), isMultiplexExternalSource(false),
- FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
+ CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
SourceMgr(PP.getSourceManager()), CollectStats(false),
CodeCompleter(CodeCompleter), CurContext(nullptr),
@@ -139,8 +159,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
- CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
- PragmaAttributeCurrentTargetDecl(nullptr),
+ CodeSegStack(nullptr), FpPragmaStack(0xffffffff), CurInitSeg(nullptr),
+ VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
@@ -153,10 +173,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TUKind(TUKind), NumSFINAEErrors(0),
FullyCheckedComparisonCategories(
static_cast<unsigned>(ComparisonCategoryType::Last) + 1),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this),
+ SatisfactionCache(Context), AccessCheckingSFINAE(false),
+ InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
@@ -379,6 +399,14 @@ Sema::~Sema() {
if (isMultiplexExternalSource)
delete ExternalSource;
+ // Delete cached satisfactions.
+ std::vector<ConstraintSatisfaction *> Satisfactions;
+ Satisfactions.reserve(Satisfactions.size());
+ for (auto &Node : SatisfactionCache)
+ Satisfactions.push_back(&Node);
+ for (auto *Node : Satisfactions)
+ delete Node;
+
threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);
// Destroys data sharing attributes stack for OpenMP
@@ -928,9 +956,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
PerformPendingInstantiations();
}
- // Finalize analysis of OpenMP-specific constructs.
- if (LangOpts.OpenMP)
- finalizeOpenMPDelayedAnalysis();
+ emitDeferredDiags();
assert(LateParsedInstantiations.empty() &&
"end of TU template instantiation should not create more "
@@ -983,6 +1009,11 @@ void Sema::ActOnEndOfTranslationUnit() {
LateParsedInstantiations.begin(),
LateParsedInstantiations.end());
LateParsedInstantiations.clear();
+
+ if (LangOpts.PCHInstantiateTemplates) {
+ llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
+ PerformPendingInstantiations();
+ }
}
DiagnoseUnterminatedPragmaPack();
@@ -1261,7 +1292,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
while (true) {
- if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) {
+ if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) ||
+ isa<RequiresExprBodyDecl>(DC)) {
DC = DC->getParent();
} else if (isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
@@ -1413,38 +1445,184 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
auto FnIt = S.DeviceKnownEmittedFns.find(FD);
while (FnIt != S.DeviceKnownEmittedFns.end()) {
+ // Respect error limit.
+ if (S.Diags.hasFatalErrorOccurred())
+ return;
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, bool ShowCallStack) {
- 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);
+namespace {
+
+/// Helper class that emits deferred diagnostic messages if an entity directly
+/// or indirectly using the function that causes the deferred diagnostic
+/// messages is known to be emitted.
+///
+/// During parsing of AST, certain diagnostic messages are recorded as deferred
+/// diagnostics since it is unknown whether the functions containing such
+/// diagnostics will be emitted. A list of potentially emitted functions and
+/// variables that may potentially trigger emission of functions are also
+/// recorded. DeferredDiagnosticsEmitter recursively visits used functions
+/// by each function to emit deferred diagnostics.
+///
+/// During the visit, certain OpenMP directives or initializer of variables
+/// with certain OpenMP attributes will cause subsequent visiting of any
+/// functions enter a state which is called OpenMP device context in this
+/// implementation. The state is exited when the directive or initializer is
+/// exited. This state can change the emission states of subsequent uses
+/// of functions.
+///
+/// Conceptually the functions or variables to be visited form a use graph
+/// where the parent node uses the child node. At any point of the visit,
+/// the tree nodes traversed from the tree root to the current node form a use
+/// stack. The emission state of the current node depends on two factors:
+/// 1. the emission state of the root node
+/// 2. whether the current node is in OpenMP device context
+/// If the function is decided to be emitted, its contained deferred diagnostics
+/// are emitted, together with the information about the use stack.
+///
+class DeferredDiagnosticsEmitter
+ : public UsedDeclVisitor<DeferredDiagnosticsEmitter> {
+public:
+ typedef UsedDeclVisitor<DeferredDiagnosticsEmitter> Inherited;
+
+ // Whether the function is already in the current use-path.
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> InUsePath;
+
+ // The current use-path.
+ llvm::SmallVector<CanonicalDeclPtr<FunctionDecl>, 4> UsePath;
+
+ // Whether the visiting of the function has been done. Done[0] is for the
+ // case not in OpenMP device context. Done[1] is for the case in OpenMP
+ // device context. We need two sets because diagnostics emission may be
+ // different depending on whether it is in OpenMP device context.
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> DoneMap[2];
+
+ // Emission state of the root node of the current use graph.
+ bool ShouldEmitRootNode;
+
+ // Current OpenMP device context level. It is initialized to 0 and each
+ // entering of device context increases it by 1 and each exit decreases
+ // it by 1. Non-zero value indicates it is currently in device context.
+ unsigned InOMPDeviceContext;
+
+ DeferredDiagnosticsEmitter(Sema &S)
+ : Inherited(S), ShouldEmitRootNode(false), InOMPDeviceContext(0) {}
+
+ void VisitOMPTargetDirective(OMPTargetDirective *Node) {
+ ++InOMPDeviceContext;
+ Inherited::VisitOMPTargetDirective(Node);
+ --InOMPDeviceContext;
+ }
+
+ void visitUsedDecl(SourceLocation Loc, Decl *D) {
+ if (isa<VarDecl>(D))
+ return;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ checkFunc(Loc, FD);
+ else
+ Inherited::visitUsedDecl(Loc, D);
+ }
+
+ void checkVar(VarDecl *VD) {
+ assert(VD->isFileVarDecl() &&
+ "Should only check file-scope variables");
+ if (auto *Init = VD->getInit()) {
+ auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD);
+ bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost ||
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Any);
+ if (IsDev)
+ ++InOMPDeviceContext;
+ this->Visit(Init);
+ if (IsDev)
+ --InOMPDeviceContext;
+ }
+ }
+
+ void checkFunc(SourceLocation Loc, FunctionDecl *FD) {
+ auto &Done = DoneMap[InOMPDeviceContext > 0 ? 1 : 0];
+ FunctionDecl *Caller = UsePath.empty() ? nullptr : UsePath.back();
+ if ((!ShouldEmitRootNode && !S.getLangOpts().OpenMP && !Caller) ||
+ S.shouldIgnoreInHostDeviceCheck(FD) || InUsePath.count(FD))
+ return;
+ // Finalize analysis of OpenMP-specific constructs.
+ if (Caller && S.LangOpts.OpenMP && UsePath.size() == 1)
+ S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc);
+ if (Caller)
+ S.DeviceKnownEmittedFns[FD] = {Caller, Loc};
+ // Always emit deferred diagnostics for the direct users. This does not
+ // lead to explosion of diagnostics since each user is visited at most
+ // twice.
+ if (ShouldEmitRootNode || InOMPDeviceContext)
+ emitDeferredDiags(FD, Caller);
+ // Do not revisit a function if the function body has been completely
+ // visited before.
+ if (!Done.insert(FD).second)
+ return;
+ InUsePath.insert(FD);
+ UsePath.push_back(FD);
+ if (auto *S = FD->getBody()) {
+ this->Visit(S);
+ }
+ UsePath.pop_back();
+ InUsePath.erase(FD);
+ }
+
+ void checkRecordedDecl(Decl *D) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ ShouldEmitRootNode = S.getEmissionStatus(FD, /*Final=*/true) ==
+ Sema::FunctionEmissionStatus::Emitted;
+ checkFunc(SourceLocation(), FD);
+ } else
+ checkVar(cast<VarDecl>(D));
+ }
+
+ // Emit any deferred diagnostics for FD
+ void emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack) {
+ auto It = S.DeviceDeferredDiags.find(FD);
+ if (It == S.DeviceDeferredDiags.end())
+ return;
+ bool HasWarningOrError = false;
+ bool FirstDiag = true;
+ for (PartialDiagnosticAt &PDAt : It->second) {
+ // Respect error limit.
+ if (S.Diags.hasFatalErrorOccurred())
+ return;
+ 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()));
+ PD.Emit(Builder);
+ }
+ // Emit the note on the first diagnostic in case too many diagnostics
+ // cause the note not emitted.
+ if (FirstDiag && HasWarningOrError && ShowCallStack) {
+ emitCallStackNotes(S, FD);
+ FirstDiag = false;
+ }
+ }
}
- S.DeviceDeferredDiags.erase(It);
+};
+} // namespace
+
+void Sema::emitDeferredDiags() {
+ if (ExternalSource)
+ ExternalSource->ReadDeclsToCheckForDeferredDiags(
+ DeclsToCheckForDeferredDiags);
+
+ if ((DeviceDeferredDiags.empty() && !LangOpts.OpenMP) ||
+ DeclsToCheckForDeferredDiags.empty())
+ return;
- // 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 && ShowCallStack)
- emitCallStackNotes(S, FD);
+ DeferredDiagnosticsEmitter DDE(*this);
+ for (auto D : DeclsToCheckForDeferredDiags)
+ DDE.checkRecordedDecl(D);
}
// In CUDA, there are some constructs which may appear in semantically-valid
@@ -1517,71 +1695,6 @@ Sema::DeviceDiagBuilder::~DeviceDiagBuilder() {
}
}
-// 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, C.Caller);
-
- // 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)
return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID)
@@ -1589,10 +1702,59 @@ Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
+
+ if (getLangOpts().SYCLIsDevice)
+ return SYCLDiagIfDeviceCode(Loc, DiagID);
+
return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID,
getCurFunctionDecl(), *this);
}
+void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) {
+ if (isUnevaluatedContext())
+ return;
+
+ Decl *C = cast<Decl>(getCurLexicalContext());
+
+ // Memcpy operations for structs containing a member with unsupported type
+ // are ok, though.
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(C)) {
+ if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
+ MD->isTrivial())
+ return;
+
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(MD))
+ if (Ctor->isCopyOrMoveConstructor() && Ctor->isTrivial())
+ return;
+ }
+
+ auto CheckType = [&](QualType Ty) {
+ if (Ty->isDependentType())
+ return;
+
+ if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) ||
+ ((Ty->isFloat128Type() ||
+ (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) &&
+ !Context.getTargetInfo().hasFloat128Type()) ||
+ (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 &&
+ !Context.getTargetInfo().hasInt128Type())) {
+ targetDiag(Loc, diag::err_device_unsupported_type)
+ << D << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
+ << Context.getTargetInfo().getTriple().str();
+ targetDiag(D->getLocation(), diag::note_defined_here) << D;
+ }
+ };
+
+ QualType Ty = D->getType();
+ CheckType(Ty);
+
+ if (const auto *FPTy = dyn_cast<FunctionProtoType>(Ty)) {
+ for (const auto &ParamTy : FPTy->param_types())
+ CheckType(ParamTy);
+ CheckType(FPTy->getReturnType());
+ }
+}
+
/// 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
@@ -1794,7 +1956,7 @@ void Sema::PopCompoundScope() {
/// Determine whether any errors occurred within this function/method/
/// block.
bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
- return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
+ return getCurFunction()->hasUnrecoverableErrorOccurred();
}
void Sema::setFunctionHasBranchIntoScope() {
@@ -2246,16 +2408,8 @@ std::string Sema::getOpenCLExtensionsFromTypeExtMap(FunctionType *FT) {
template <typename T, typename MapT>
std::string Sema::getOpenCLExtensionsFromExtMap(T *FDT, MapT &Map) {
- std::string ExtensionNames = "";
auto Loc = Map.find(FDT);
-
- for (auto const& I : Loc->second) {
- ExtensionNames += I;
- ExtensionNames += " ";
- }
- ExtensionNames.pop_back();
-
- return ExtensionNames;
+ return llvm::join(Loc->second, " ");
}
bool Sema::isOpenCLDisabledDecl(Decl *FD) {