diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f52816e12efe4..f49bc724c96c8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -55,6 +55,7 @@ #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaBase.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" @@ -422,7 +423,7 @@ enum class TemplateDeductionResult { /// Sema - This implements semantic analysis and AST building for C. /// \nosubgrouping -class Sema final { +class Sema final : public SemaBase { // Table of Contents // ----------------- // 1. Semantic Analysis (Sema.cpp) @@ -512,195 +513,6 @@ class Sema final { /// void addExternalSource(ExternalSemaSource *E); - /// Helper class that creates diagnostics with optional - /// template instantiation stacks. - /// - /// This class provides a wrapper around the basic DiagnosticBuilder - /// class that emits diagnostics. ImmediateDiagBuilder is - /// responsible for emitting the diagnostic (as DiagnosticBuilder - /// does) and, if the diagnostic comes from inside a template - /// instantiation, printing the template instantiation stack as - /// well. - class ImmediateDiagBuilder : public DiagnosticBuilder { - Sema &SemaRef; - unsigned DiagID; - - public: - ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} - ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} - - // This is a cunning lie. DiagnosticBuilder actually performs move - // construction in its copy constructor (but due to varied uses, it's not - // possible to conveniently express this as actual move construction). So - // the default copy ctor here is fine, because the base class disables the - // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op - // in that case anwyay. - ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; - - ~ImmediateDiagBuilder() { - // If we aren't active, there is nothing to do. - if (!isActive()) - return; - - // Otherwise, we need to emit the diagnostic. First clear the diagnostic - // builder itself so it won't emit the diagnostic in its own destructor. - // - // This seems wasteful, in that as written the DiagnosticBuilder dtor will - // do its own needless checks to see if the diagnostic needs to be - // emitted. However, because we take care to ensure that the builder - // objects never escape, a sufficiently smart compiler will be able to - // eliminate that code. - Clear(); - - // Dispatch to Sema to emit the diagnostic. - SemaRef.EmitCurrentDiagnostic(DiagID); - } - - /// Teach operator<< to produce an object of the correct type. - template - friend const ImmediateDiagBuilder & - operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { - const DiagnosticBuilder &BaseDiag = Diag; - BaseDiag << Value; - return Diag; - } - - // It is necessary to limit this to rvalue reference to avoid calling this - // function with a bitfield lvalue argument since non-const reference to - // bitfield is not allowed. - template ::value>> - const ImmediateDiagBuilder &operator<<(T &&V) const { - const DiagnosticBuilder &BaseDiag = *this; - BaseDiag << std::move(V); - return *this; - } - }; - - /// A generic diagnostic builder for errors which may or may not be deferred. - /// - /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) - /// which are not allowed to appear inside __device__ functions and are - /// allowed to appear in __host__ __device__ functions only if the host+device - /// function is never codegen'ed. - /// - /// To handle this, we use the notion of "deferred diagnostics", where we - /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. - /// - /// This class lets you emit either a regular diagnostic, a deferred - /// diagnostic, or no diagnostic at all, according to an argument you pass to - /// its constructor, thus simplifying the process of creating these "maybe - /// deferred" diagnostics. - class SemaDiagnosticBuilder { - public: - enum Kind { - /// Emit no diagnostics. - K_Nop, - /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). - K_Immediate, - /// Emit the diagnostic immediately, and, if it's a warning or error, also - /// emit a call stack showing how this function can be reached by an a - /// priori known-emitted function. - K_ImmediateWithCallStack, - /// Create a deferred diagnostic, which is emitted only if the function - /// it's attached to is codegen'ed. Also emit a call stack as with - /// K_ImmediateWithCallStack. - K_Deferred - }; - - SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, - const FunctionDecl *Fn, Sema &S); - SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); - SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; - - // The copy and move assignment operator is defined as deleted pending - // further motivation. - SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; - SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; - - ~SemaDiagnosticBuilder(); - - bool isImmediate() const { return ImmediateDiag.has_value(); } - - /// Convertible to bool: True if we immediately emitted an error, false if - /// we didn't emit an error or we created a deferred error. - /// - /// Example usage: - /// - /// if (SemaDiagnosticBuilder(...) << foo << bar) - /// return ExprError(); - /// - /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably - /// want to use these instead of creating a SemaDiagnosticBuilder yourself. - operator bool() const { return isImmediate(); } - - template - friend const SemaDiagnosticBuilder & - operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { - if (Diag.ImmediateDiag) - *Diag.ImmediateDiag << Value; - else if (Diag.PartialDiagId) - Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second - << Value; - return Diag; - } - - // It is necessary to limit this to rvalue reference to avoid calling this - // function with a bitfield lvalue argument since non-const reference to - // bitfield is not allowed. - template ::value>> - const SemaDiagnosticBuilder &operator<<(T &&V) const { - if (ImmediateDiag) - *ImmediateDiag << std::move(V); - else if (PartialDiagId) - S.DeviceDeferredDiags[Fn][*PartialDiagId].second << std::move(V); - return *this; - } - - friend const SemaDiagnosticBuilder & - operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD) { - if (Diag.ImmediateDiag) - PD.Emit(*Diag.ImmediateDiag); - else if (Diag.PartialDiagId) - Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; - return Diag; - } - - void AddFixItHint(const FixItHint &Hint) const { - if (ImmediateDiag) - ImmediateDiag->AddFixItHint(Hint); - else if (PartialDiagId) - S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); - } - - friend ExprResult ExprError(const SemaDiagnosticBuilder &) { - return ExprError(); - } - friend StmtResult StmtError(const SemaDiagnosticBuilder &) { - return StmtError(); - } - operator ExprResult() const { return ExprError(); } - operator StmtResult() const { return StmtError(); } - operator TypeResult() const { return TypeError(); } - operator DeclResult() const { return DeclResult(true); } - operator MemInitResult() const { return MemInitResult(true); } - - private: - Sema &S; - SourceLocation Loc; - unsigned DiagID; - const FunctionDecl *Fn; - bool ShowCallStack; - - // Invariant: At most one of these Optionals has a value. - // FIXME: Switch these to a Variant once that exists. - std::optional ImmediateDiag; - std::optional PartialDiagId; - }; - void PrintStats() const; /// Warn that the stack is nearly exhausted. @@ -742,14 +554,6 @@ class Sema final { void addImplicitTypedef(StringRef Name, QualType T); - /// Emit a diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, - bool DeferHint = false); - - /// Emit a partial diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, - bool DeferHint = false); - /// Whether uncompilable error has occurred. This includes error happens /// in deferred diagnostics. bool hasUncompilableErrorOccurred() const; @@ -13115,9 +12919,7 @@ class Sema final { /// Diagnostics that are emitted only if we discover that the given function /// must be codegen'ed. Because handling these correctly adds overhead to /// compilation, this is currently only enabled for CUDA compilations. - llvm::DenseMap, - std::vector> - DeviceDeferredDiags; + SemaDiagnosticBuilder::DeferredDiagnosticsType DeviceDeferredDiags; /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the /// key in a hashtable, both the FD and location are hashed. diff --git a/clang/include/clang/Sema/SemaBase.h b/clang/include/clang/Sema/SemaBase.h new file mode 100644 index 0000000000000..ff718022fca03 --- /dev/null +++ b/clang/include/clang/Sema/SemaBase.h @@ -0,0 +1,224 @@ +//===--- SemaBase.h - Common utilities for semantic analysis-----*- C++ -*-===// +// +// 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 the SemaBase class, which provides utilities for Sema +// and its parts like SemaOpenACC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMABASE_H +#define LLVM_CLANG_SEMA_SEMABASE_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Redeclarable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include +#include + +namespace clang { + +class ASTContext; +class DiagnosticsEngine; +class LangOptions; +class Sema; + +class SemaBase { +public: + SemaBase(Sema &S); + + Sema &SemaRef; + + ASTContext &getASTContext() const; + DiagnosticsEngine &getDiagnostics() const; + const LangOptions &getLangOpts() const; + + /// Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. ImmediateDiagBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class ImmediateDiagBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + + // This is a cunning lie. DiagnosticBuilder actually performs move + // construction in its copy constructor (but due to varied uses, it's not + // possible to conveniently express this as actual move construction). So + // the default copy ctor here is fine, because the base class disables the + // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op + // in that case anwyay. + ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; + + ~ImmediateDiagBuilder(); + + /// Teach operator<< to produce an object of the correct type. + template + friend const ImmediateDiagBuilder & + operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template ::value>> + const ImmediateDiagBuilder &operator<<(T &&V) const { + const DiagnosticBuilder &BaseDiag = *this; + BaseDiag << std::move(V); + return *this; + } + }; + + /// A generic diagnostic builder for errors which may or may not be deferred. + /// + /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) + /// which are not allowed to appear inside __device__ functions and are + /// allowed to appear in __host__ __device__ functions only if the host+device + /// function is never codegen'ed. + /// + /// To handle this, we use the notion of "deferred diagnostics", where we + /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. + /// + /// This class lets you emit either a regular diagnostic, a deferred + /// diagnostic, or no diagnostic at all, according to an argument you pass to + /// its constructor, thus simplifying the process of creating these "maybe + /// deferred" diagnostics. + class SemaDiagnosticBuilder { + public: + enum Kind { + /// Emit no diagnostics. + K_Nop, + /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). + K_Immediate, + /// Emit the diagnostic immediately, and, if it's a warning or error, also + /// emit a call stack showing how this function can be reached by an a + /// priori known-emitted function. + K_ImmediateWithCallStack, + /// Create a deferred diagnostic, which is emitted only if the function + /// it's attached to is codegen'ed. Also emit a call stack as with + /// K_ImmediateWithCallStack. + K_Deferred + }; + + SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, + const FunctionDecl *Fn, Sema &S); + SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); + SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; + + // The copy and move assignment operator is defined as deleted pending + // further motivation. + SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; + SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; + + ~SemaDiagnosticBuilder(); + + bool isImmediate() const { return ImmediateDiag.has_value(); } + + /// Convertible to bool: True if we immediately emitted an error, false if + /// we didn't emit an error or we created a deferred error. + /// + /// Example usage: + /// + /// if (SemaDiagnosticBuilder(...) << foo << bar) + /// return ExprError(); + /// + /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably + /// want to use these instead of creating a SemaDiagnosticBuilder yourself. + operator bool() const { return isImmediate(); } + + template + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { + if (Diag.ImmediateDiag) + *Diag.ImmediateDiag << Value; + else if (Diag.PartialDiagId) + Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second + << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template ::value>> + const SemaDiagnosticBuilder &operator<<(T &&V) const { + if (ImmediateDiag) + *ImmediateDiag << std::move(V); + else if (PartialDiagId) + getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V); + return *this; + } + + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD); + + void AddFixItHint(const FixItHint &Hint) const; + + friend ExprResult ExprError(const SemaDiagnosticBuilder &) { + return ExprError(); + } + friend StmtResult StmtError(const SemaDiagnosticBuilder &) { + return StmtError(); + } + operator ExprResult() const { return ExprError(); } + operator StmtResult() const { return StmtError(); } + operator TypeResult() const { return TypeError(); } + operator DeclResult() const { return DeclResult(true); } + operator MemInitResult() const { return MemInitResult(true); } + + using DeferredDiagnosticsType = + llvm::DenseMap, + std::vector>; + + private: + Sema &S; + SourceLocation Loc; + unsigned DiagID; + const FunctionDecl *Fn; + bool ShowCallStack; + + // Invariant: At most one of these Optionals has a value. + // FIXME: Switch these to a Variant once that exists. + std::optional ImmediateDiag; + std::optional PartialDiagId; + + DeferredDiagnosticsType &getDeviceDeferredDiags() const; + }; + + /// Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint = false); + + /// Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, + bool DeferHint = false); +}; + +} // namespace clang + +#endif diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 7f50d7889ad79..ad4cff04ec9c6 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -18,24 +18,14 @@ #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaBase.h" namespace clang { -class ASTContext; -class DiagnosticEngine; -class LangOptions; -class Sema; - -class SemaOpenACC { +class SemaOpenACC : public SemaBase { public: SemaOpenACC(Sema &S); - ASTContext &getASTContext() const; - DiagnosticsEngine &getDiagnostics() const; - const LangOptions &getLangOpts() const; - - Sema &SemaRef; - /// Called after parsing an OpenACC Clause so that it can be checked. bool ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc); diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index e8bff07ced0cf..ab3b813a9ccd9 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangSema SemaAttr.cpp SemaAPINotes.cpp SemaAvailability.cpp + SemaBase.cpp SemaCXXScopeSpec.cpp SemaCast.cpp SemaChecking.cpp diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b7e4fc0ac9b5b..6b8e88e885003 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -190,14 +190,15 @@ const uint64_t Sema::MaximumAlignment; Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) - : CollectStats(false), TUKind(TUKind), CurFPFeatures(pp.getLangOpts()), - LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), - Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - APINotes(SourceMgr, LangOpts), AnalysisWarnings(*this), - ThreadSafetyDeclCache(nullptr), LateTemplateParser(nullptr), - LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), - CurContext(nullptr), ExternalSource(nullptr), CurScope(nullptr), - Ident_super(nullptr), OpenACCPtr(std::make_unique(*this)), + : SemaBase(*this), CollectStats(false), TUKind(TUKind), + CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), + Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), + SourceMgr(PP.getSourceManager()), APINotes(SourceMgr, LangOpts), + AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), + LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), + OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr), + CurScope(nullptr), Ident_super(nullptr), + OpenACCPtr(std::make_unique(*this)), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()), @@ -1612,11 +1613,6 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { PrintContextStack(); } -Sema::SemaDiagnosticBuilder -Sema::Diag(SourceLocation Loc, const PartialDiagnostic &PD, bool DeferHint) { - return Diag(Loc, PD.getDiagID(), DeferHint) << PD; -} - bool Sema::hasUncompilableErrorOccurred() const { if (getDiagnostics().hasUncompilableErrorOccurred()) return true; @@ -1911,29 +1907,6 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) { FD, *this); } -Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID, - bool DeferHint) { - bool IsError = Diags.getDiagnosticIDs()->isDefaultMappingAsError(DiagID); - bool ShouldDefer = getLangOpts().CUDA && LangOpts.GPUDeferDiag && - DiagnosticIDs::isDeferrable(DiagID) && - (DeferHint || DeferDiags || !IsError); - auto SetIsLastErrorImmediate = [&](bool Flag) { - if (IsError) - IsLastErrorImmediate = Flag; - }; - if (!ShouldDefer) { - SetIsLastErrorImmediate(true); - return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, - DiagID, getCurFunctionDecl(), *this); - } - - SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice - ? CUDADiagIfDeviceCode(Loc, DiagID) - : CUDADiagIfHostCode(Loc, DiagID); - SetIsLastErrorImmediate(DB.isImmediate()); - return DB; -} - void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (isUnevaluatedContext() || Ty.isNull()) return; diff --git a/clang/lib/Sema/SemaBase.cpp b/clang/lib/Sema/SemaBase.cpp new file mode 100644 index 0000000000000..95c0cfbe283b0 --- /dev/null +++ b/clang/lib/Sema/SemaBase.cpp @@ -0,0 +1,85 @@ +#include "clang/Sema/SemaBase.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaBase::SemaBase(Sema &S) : SemaRef(S) {} + +ASTContext &SemaBase::getASTContext() const { return SemaRef.Context; } +DiagnosticsEngine &SemaBase::getDiagnostics() const { return SemaRef.Diags; } +const LangOptions &SemaBase::getLangOpts() const { return SemaRef.LangOpts; } + +SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() { + // If we aren't active, there is nothing to do. + if (!isActive()) + return; + + // Otherwise, we need to emit the diagnostic. First clear the diagnostic + // builder itself so it won't emit the diagnostic in its own destructor. + // + // This seems wasteful, in that as written the DiagnosticBuilder dtor will + // do its own needless checks to see if the diagnostic needs to be + // emitted. However, because we take care to ensure that the builder + // objects never escape, a sufficiently smart compiler will be able to + // eliminate that code. + Clear(); + + // Dispatch to Sema to emit the diagnostic. + SemaRef.EmitCurrentDiagnostic(DiagID); +} + +const SemaBase::SemaDiagnosticBuilder & +operator<<(const SemaBase::SemaDiagnosticBuilder &Diag, + const PartialDiagnostic &PD) { + if (Diag.ImmediateDiag) + PD.Emit(*Diag.ImmediateDiag); + else if (Diag.PartialDiagId) + Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; + return Diag; +} + +void SemaBase::SemaDiagnosticBuilder::AddFixItHint( + const FixItHint &Hint) const { + if (ImmediateDiag) + ImmediateDiag->AddFixItHint(Hint); + else if (PartialDiagId) + S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); +} + +llvm::DenseMap, + std::vector> & +SemaBase::SemaDiagnosticBuilder::getDeviceDeferredDiags() const { + return S.DeviceDeferredDiags; +} + +Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint) { + bool IsError = + getDiagnostics().getDiagnosticIDs()->isDefaultMappingAsError(DiagID); + bool ShouldDefer = getLangOpts().CUDA && getLangOpts().GPUDeferDiag && + DiagnosticIDs::isDeferrable(DiagID) && + (DeferHint || SemaRef.DeferDiags || !IsError); + auto SetIsLastErrorImmediate = [&](bool Flag) { + if (IsError) + SemaRef.IsLastErrorImmediate = Flag; + }; + if (!ShouldDefer) { + SetIsLastErrorImmediate(true); + return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, + DiagID, SemaRef.getCurFunctionDecl(), SemaRef); + } + + SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice + ? SemaRef.CUDADiagIfDeviceCode(Loc, DiagID) + : SemaRef.CUDADiagIfHostCode(Loc, DiagID); + SetIsLastErrorImmediate(DB.isImmediate()); + return DB; +} + +Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, + const PartialDiagnostic &PD, + bool DeferHint) { + return Diag(Loc, PD.getDiagID(), DeferHint) << PD; +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 86ffa5ad74c13..f66cc1a69ce44 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -11,8 +11,8 @@ /// //===----------------------------------------------------------------------===// -#include "clang/AST/StmtOpenACC.h" #include "clang/Sema/SemaOpenACC.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Sema/Sema.h" @@ -31,19 +31,14 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: if (!IsStmt) - return S.SemaRef.Diag(StartLoc, diag::err_acc_construct_appertainment) - << K; + return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K; break; } return false; } } // namespace -SemaOpenACC::SemaOpenACC(Sema &S) : SemaRef(S) {} - -ASTContext &SemaOpenACC::getASTContext() const { return SemaRef.Context; } -DiagnosticsEngine &SemaOpenACC::getDiagnostics() const { return SemaRef.Diags; } -const LangOptions &SemaOpenACC::getLangOpts() const { return SemaRef.LangOpts; } +SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {} bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc) { @@ -53,8 +48,7 @@ bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind, // whatever it can do. This function will eventually need to start returning // some sort of Clause AST type, but for now just return true/false based on // success. - return SemaRef.Diag(StartLoc, diag::warn_acc_clause_unimplemented) - << ClauseKind; + return Diag(StartLoc, diag::warn_acc_clause_unimplemented) << ClauseKind; } void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc) { @@ -72,7 +66,7 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, // here as these constructs do not take any arguments. break; default: - SemaRef.Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; + Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; break; } }