[clang][NFC] Introduce SemaBase (#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` 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.
This commit is contained in:
committed by
GitHub
parent
f5d7e755b8
commit
d288444447
@@ -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 @@ public:
|
||||
///
|
||||
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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
/// 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.
|
||||
|
||||
224
clang/include/clang/Sema/SemaBase.h
Normal file
224
clang/include/clang/Sema/SemaBase.h
Normal file
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ add_clang_library(clangSema
|
||||
SemaAttr.cpp
|
||||
SemaAPINotes.cpp
|
||||
SemaAvailability.cpp
|
||||
SemaBase.cpp
|
||||
SemaCXXScopeSpec.cpp
|
||||
SemaCast.cpp
|
||||
SemaChecking.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;
|
||||
|
||||
85
clang/lib/Sema/SemaBase.cpp
Normal file
85
clang/lib/Sema/SemaBase.cpp
Normal file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user