[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:
Vlad Serebrennikov
2024-04-06 15:10:48 +04:00
committed by GitHub
parent f5d7e755b8
commit d288444447
7 changed files with 329 additions and 260 deletions

View File

@@ -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.

View 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

View File

@@ -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);

View File

@@ -29,6 +29,7 @@ add_clang_library(clangSema
SemaAttr.cpp
SemaAPINotes.cpp
SemaAvailability.cpp
SemaBase.cpp
SemaCXXScopeSpec.cpp
SemaCast.cpp
SemaChecking.cpp

View File

@@ -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;

View 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

View File

@@ -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;
}
}