-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang][NFC] Introduce SemaBase
#87634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This is a follow-up to llvm#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.
@llvm/pr-subscribers-clang Author: Vlad Serebrennikov (Endilll) ChangesThis is a follow-up to #84184. Multiple reviewers there pointed out to me that we should have a common base class for The intent is to keep Apart of shuffling code around, this patch introduces a helper private function Patch is 28.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/87634.diff 7 Files Affected:
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)
- : Coll...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it, this is definitely a positive direction here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks!
This patch introduces `SemaHLSL` class, and moves some HLSL-related functions there. No functional changes intended. Removing "HLSL" from function names inside `SemaHLSL` is left for a subsequent PR by HLSL contributors, if they deem that desirable. This is a part of the effort to split `Sema` into smaller manageable parts, and follows the example of OpenACC. See #82217, #84184, #87634 for additional context.
This patch moves CUDA-related `Sema` function into new `SemaCUDA` class, following the recent example of SYCL, OpenACC, and HLSL. This is a part of the effort to split Sema. Additional context can be found in llvm#82217, llvm#84184, llvm#87634.
This is a follow-up to #84184. Multiple reviewers there pointed out to me that we should have a common base class for
Sema
andSemaOpenACC
to avoid code duplication for common helpers likegetLangOpts()
. On top of that,Diag()
function was requested forSemaOpenACC
. This patch delivers both.The intent is to keep
SemaBase
as small as possible, as things there are globally available acrossSema
and its parts without any additional effort from usage side. Overused, this can undermine the whole endeavor of splittingSema
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, whereSema
can't be complete.