[clang] [clang][NFC] Introduce `SemaBase` (PR #87634)
Vlad Serebrennikov via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 5 21:17:02 PDT 2024
https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/87634
>From 311e2ef14dda46686b473e813028a2c3b2ac1254 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Thu, 4 Apr 2024 16:07:35 +0300
Subject: [PATCH] [clang][NFC] Introduce `SemaBase`
This is a follow-up to #84184. Multiple reviewers there pointed out to me that we should have a common base class for `Sema` and `SemaOpenACC` to avoid code duplication for common helpers like `getLangOpts`. On top of that, `Diag()` function was requested for `SemaOpenACC`. This patch delivers both.
The intent is to keep `SemaBase` as small as possible, as things there are globally available across `Sema` and its parts without any additional effort from usage side. Overused, this can undermine the whole endeavor of splitting `Sema` apart.
Apart of shuffling code around, this patch introduces a helper private function `SemaDiagnosticBuilder::getDeviceDeferredDiags()`, the sole purpose of which is to encapsulate member access into (incomplete) `Sema` for function templates defined in the header, where `Sema` can't be complete.
---
clang/include/clang/Sema/Sema.h | 204 +---------------------
clang/include/clang/Sema/SemaBase.h | 224 +++++++++++++++++++++++++
clang/include/clang/Sema/SemaOpenACC.h | 14 +-
clang/lib/Sema/CMakeLists.txt | 1 +
clang/lib/Sema/Sema.cpp | 45 +----
clang/lib/Sema/SemaBase.cpp | 85 ++++++++++
clang/lib/Sema/SemaOpenACC.cpp | 16 +-
7 files changed, 329 insertions(+), 260 deletions(-)
create mode 100644 clang/include/clang/Sema/SemaBase.h
create mode 100644 clang/lib/Sema/SemaBase.cpp
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 8c98d8c7fef7a7..e97bb45bf04739 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 <typename T>
- 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 <typename T,
- typename = std::enable_if_t<!std::is_lvalue_reference<T>::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 <typename T>
- 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 <typename T,
- typename = std::enable_if_t<!std::is_lvalue_reference<T>::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<ImmediateDiagBuilder> ImmediateDiag;
- std::optional<unsigned> 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;
@@ -13105,9 +12909,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<CanonicalDeclPtr<const FunctionDecl>,
- std::vector<PartialDiagnosticAt>>
- 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 00000000000000..ff718022fca03c
--- /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 <optional>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+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 <typename T>
+ 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 <typename T,
+ typename = std::enable_if_t<!std::is_lvalue_reference<T>::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 <typename T>
+ 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 <typename T,
+ typename = std::enable_if_t<!std::is_lvalue_reference<T>::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<CanonicalDeclPtr<const FunctionDecl>,
+ std::vector<PartialDiagnosticAt>>;
+
+ 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<ImmediateDiagBuilder> ImmediateDiag;
+ std::optional<unsigned> 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 7f50d7889ad79b..ad4cff04ec9c65 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 e8bff07ced0cfa..ab3b813a9ccd97 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 b7e4fc0ac9b5b2..6b8e88e8850035 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<SemaOpenACC>(*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<SemaOpenACC>(*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 00000000000000..95c0cfbe283b0e
--- /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<CanonicalDeclPtr<const FunctionDecl>,
+ std::vector<PartialDiagnosticAt>> &
+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 2ac994cac71e19..db248bf5bd47f9 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;
}
}
More information about the cfe-commits
mailing list