[clang] Extend diagnose_if to accept more detailed warning information, take 2 (#119712)
This is take two of #70976. This iteration of the patch makes sure that custom diagnostics without any warning group don't get promoted by `-Werror` or `-Wfatal-errors`. This implements parts of the extension proposed in https://discourse.llvm.org/t/exposing-the-diagnostic-engine-to-c/73092/7. Specifically, this makes it possible to specify a diagnostic group in an optional third argument.
This commit is contained in:
parent
aab25f20f6
commit
0865ecc515
@ -577,7 +577,17 @@ std::vector<Diag> StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) {
|
||||
for (auto &Diag : Output) {
|
||||
if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) {
|
||||
// Warnings controlled by -Wfoo are better recognized by that name.
|
||||
StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(Diag.ID);
|
||||
StringRef Warning = [&] {
|
||||
if (OrigSrcMgr) {
|
||||
return OrigSrcMgr->getDiagnostics()
|
||||
.getDiagnosticIDs()
|
||||
->getWarningOptionForDiag(Diag.ID);
|
||||
}
|
||||
if (!DiagnosticIDs::IsCustomDiag(Diag.ID))
|
||||
return DiagnosticIDs{}.getWarningOptionForDiag(Diag.ID);
|
||||
return StringRef{};
|
||||
}();
|
||||
|
||||
if (!Warning.empty()) {
|
||||
Diag.Name = ("-W" + Warning).str();
|
||||
} else {
|
||||
@ -894,20 +904,23 @@ void StoreDiags::flushLastDiag() {
|
||||
Output.push_back(std::move(*LastDiag));
|
||||
}
|
||||
|
||||
bool isBuiltinDiagnosticSuppressed(unsigned ID,
|
||||
bool isDiagnosticSuppressed(const clang::Diagnostic &Diag,
|
||||
const llvm::StringSet<> &Suppress,
|
||||
const LangOptions &LangOpts) {
|
||||
// Don't complain about header-only stuff in mainfiles if it's a header.
|
||||
// FIXME: would be cleaner to suppress in clang, once we decide whether the
|
||||
// behavior should be to silently-ignore or respect the pragma.
|
||||
if (ID == diag::pp_pragma_sysheader_in_main_file && LangOpts.IsHeaderFile)
|
||||
if (Diag.getID() == diag::pp_pragma_sysheader_in_main_file &&
|
||||
LangOpts.IsHeaderFile)
|
||||
return true;
|
||||
|
||||
if (const char *CodePtr = getDiagnosticCode(ID)) {
|
||||
if (const char *CodePtr = getDiagnosticCode(Diag.getID())) {
|
||||
if (Suppress.contains(normalizeSuppressedCode(CodePtr)))
|
||||
return true;
|
||||
}
|
||||
StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(ID);
|
||||
StringRef Warning =
|
||||
Diag.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
|
||||
Diag.getID());
|
||||
if (!Warning.empty() && Suppress.contains(Warning))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -181,11 +181,11 @@ private:
|
||||
};
|
||||
|
||||
/// Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
|
||||
bool isBuiltinDiagnosticSuppressed(unsigned ID,
|
||||
bool isDiagnosticSuppressed(const clang::Diagnostic &Diag,
|
||||
const llvm::StringSet<> &Suppressed,
|
||||
const LangOptions &);
|
||||
/// Take a user-specified diagnostic code, and convert it to a normalized form
|
||||
/// stored in the config and consumed by isBuiltinDiagnosticsSuppressed.
|
||||
/// stored in the config and consumed by isDiagnosticsSuppressed.
|
||||
///
|
||||
/// (This strips err_ and -W prefix so we can match with or without them.)
|
||||
llvm::StringRef normalizeSuppressedCode(llvm::StringRef);
|
||||
|
@ -342,7 +342,7 @@ void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
|
||||
if (Enable) {
|
||||
if (Diags.getDiagnosticLevel(ID, SourceLocation()) <
|
||||
DiagnosticsEngine::Warning) {
|
||||
auto Group = DiagnosticIDs::getGroupForDiag(ID);
|
||||
auto Group = Diags.getDiagnosticIDs()->getGroupForDiag(ID);
|
||||
if (!Group || !EnabledGroups(*Group))
|
||||
continue;
|
||||
Diags.setSeverity(ID, diag::Severity::Warning, SourceLocation());
|
||||
@ -585,7 +585,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
|
||||
ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
|
||||
const clang::Diagnostic &Info) {
|
||||
if (Cfg.Diagnostics.SuppressAll ||
|
||||
isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress,
|
||||
isDiagnosticSuppressed(Info, Cfg.Diagnostics.Suppress,
|
||||
Clang->getLangOpts()))
|
||||
return DiagnosticsEngine::Ignored;
|
||||
|
||||
|
@ -622,7 +622,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
|
||||
PreambleDiagnostics.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
|
||||
const clang::Diagnostic &Info) {
|
||||
if (Cfg.Diagnostics.SuppressAll ||
|
||||
isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress,
|
||||
isDiagnosticSuppressed(Info, Cfg.Diagnostics.Suppress,
|
||||
CI.getLangOpts()))
|
||||
return DiagnosticsEngine::Ignored;
|
||||
switch (Info.getID()) {
|
||||
|
@ -298,20 +298,41 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
|
||||
"unreachable-code", "unused-variable",
|
||||
"typecheck_bool_condition",
|
||||
"unexpected_friend", "warn_alloca"));
|
||||
EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
|
||||
diag::warn_unreachable, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
|
||||
new clang::IgnoringDiagConsumer);
|
||||
|
||||
using Diag = clang::Diagnostic;
|
||||
{
|
||||
auto D = DiagEngine.Report(diag::warn_unreachable);
|
||||
EXPECT_TRUE(isDiagnosticSuppressed(
|
||||
Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
}
|
||||
// Subcategory not respected/suppressed.
|
||||
EXPECT_FALSE(isBuiltinDiagnosticSuppressed(
|
||||
diag::warn_unreachable_break, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
|
||||
diag::warn_unused_variable, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::err_typecheck_bool_condition,
|
||||
Conf.Diagnostics.Suppress,
|
||||
LangOptions()));
|
||||
EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
|
||||
diag::err_unexpected_friend, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
EXPECT_TRUE(isBuiltinDiagnosticSuppressed(
|
||||
diag::warn_alloca, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
{
|
||||
auto D = DiagEngine.Report(diag::warn_unreachable_break);
|
||||
EXPECT_FALSE(isDiagnosticSuppressed(
|
||||
Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
}
|
||||
{
|
||||
auto D = DiagEngine.Report(diag::warn_unused_variable);
|
||||
EXPECT_TRUE(isDiagnosticSuppressed(
|
||||
Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
}
|
||||
{
|
||||
auto D = DiagEngine.Report(diag::err_typecheck_bool_condition);
|
||||
EXPECT_TRUE(isDiagnosticSuppressed(
|
||||
Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
}
|
||||
{
|
||||
auto D = DiagEngine.Report(diag::err_unexpected_friend);
|
||||
EXPECT_TRUE(isDiagnosticSuppressed(
|
||||
Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
}
|
||||
{
|
||||
auto D = DiagEngine.Report(diag::warn_alloca);
|
||||
EXPECT_TRUE(isDiagnosticSuppressed(
|
||||
Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));
|
||||
}
|
||||
|
||||
Frag.Diagnostics.Suppress.emplace_back("*");
|
||||
EXPECT_TRUE(compileAndApply());
|
||||
|
@ -3458,18 +3458,16 @@ def DiagnoseIf : InheritableAttr {
|
||||
let Spellings = [GNU<"diagnose_if">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>;
|
||||
let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
|
||||
EnumArgument<"DiagnosticType", "DiagnosticType",
|
||||
EnumArgument<"DefaultSeverity",
|
||||
"DefaultSeverity",
|
||||
/*is_string=*/true,
|
||||
["error", "warning"],
|
||||
["DT_Error", "DT_Warning"]>,
|
||||
["DS_error", "DS_warning"]>,
|
||||
StringArgument<"WarningGroup", /*optional*/ 1>,
|
||||
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
|
||||
DeclArgument<Named, "Parent", 0, /*fake*/ 1>];
|
||||
let InheritEvenIfAlreadyPresent = 1;
|
||||
let LateParsed = LateAttrParseStandard;
|
||||
let AdditionalMembers = [{
|
||||
bool isError() const { return diagnosticType == DT_Error; }
|
||||
bool isWarning() const { return diagnosticType == DT_Warning; }
|
||||
}];
|
||||
let TemplateDependent = 1;
|
||||
let Documentation = [DiagnoseIfDocs];
|
||||
}
|
||||
|
@ -375,10 +375,12 @@ private:
|
||||
// Map extensions to warnings or errors?
|
||||
diag::Severity ExtBehavior = diag::Severity::Ignored;
|
||||
|
||||
DiagState()
|
||||
DiagnosticIDs &DiagIDs;
|
||||
|
||||
DiagState(DiagnosticIDs &DiagIDs)
|
||||
: IgnoreAllWarnings(false), EnableAllWarnings(false),
|
||||
WarningsAsErrors(false), ErrorsAsFatal(false),
|
||||
SuppressSystemWarnings(false) {}
|
||||
SuppressSystemWarnings(false), DiagIDs(DiagIDs) {}
|
||||
|
||||
using iterator = llvm::DenseMap<unsigned, DiagnosticMapping>::iterator;
|
||||
using const_iterator =
|
||||
@ -893,6 +895,8 @@ public:
|
||||
/// \param FormatString A fixed diagnostic format string that will be hashed
|
||||
/// and mapped to a unique DiagID.
|
||||
template <unsigned N>
|
||||
// TODO: Deprecate this once all uses are removed from Clang.
|
||||
// [[deprecated("Use a CustomDiagDesc instead of a Level")]]
|
||||
unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) {
|
||||
return Diags->getCustomDiagID((DiagnosticIDs::Level)L,
|
||||
StringRef(FormatString, N - 1));
|
||||
|
@ -26,6 +26,7 @@ namespace clang {
|
||||
#include "clang/Basic/DiagnosticGroups.inc"
|
||||
#undef CATEGORY
|
||||
#undef DIAG_ENTRY
|
||||
NUM_GROUPS
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
@ -14,6 +14,7 @@
|
||||
#ifndef LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
|
||||
#define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
|
||||
|
||||
#include "clang/Basic/DiagnosticCategories.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
@ -84,7 +85,7 @@ namespace clang {
|
||||
/// to either Ignore (nothing), Remark (emit a remark), Warning
|
||||
/// (emit a warning) or Error (emit as an error). It allows clients to
|
||||
/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
|
||||
enum class Severity {
|
||||
enum class Severity : uint8_t {
|
||||
// NOTE: 0 means "uncomputed".
|
||||
Ignored = 1, ///< Do not present this diagnostic, ignore it.
|
||||
Remark = 2, ///< Present this diagnostic as a remark.
|
||||
@ -181,13 +182,96 @@ public:
|
||||
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
|
||||
public:
|
||||
/// The level of the diagnostic, after it has been through mapping.
|
||||
enum Level {
|
||||
Ignored, Note, Remark, Warning, Error, Fatal
|
||||
enum Level : uint8_t { Ignored, Note, Remark, Warning, Error, Fatal };
|
||||
|
||||
// Diagnostic classes.
|
||||
enum Class {
|
||||
CLASS_INVALID = 0x00,
|
||||
CLASS_NOTE = 0x01,
|
||||
CLASS_REMARK = 0x02,
|
||||
CLASS_WARNING = 0x03,
|
||||
CLASS_EXTENSION = 0x04,
|
||||
CLASS_ERROR = 0x05
|
||||
};
|
||||
|
||||
static bool IsCustomDiag(diag::kind Diag) {
|
||||
return Diag >= diag::DIAG_UPPER_LIMIT;
|
||||
}
|
||||
|
||||
class CustomDiagDesc {
|
||||
LLVM_PREFERRED_TYPE(diag::Severity)
|
||||
unsigned DefaultSeverity : 3;
|
||||
LLVM_PREFERRED_TYPE(Class)
|
||||
unsigned DiagClass : 3;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned ShowInSystemHeader : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned ShowInSystemMacro : 1;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned HasGroup : 1;
|
||||
diag::Group Group;
|
||||
std::string Description;
|
||||
|
||||
auto get_as_tuple() const {
|
||||
return std::tuple(DefaultSeverity, DiagClass, ShowInSystemHeader,
|
||||
ShowInSystemMacro, HasGroup, Group,
|
||||
std::string_view{Description});
|
||||
}
|
||||
|
||||
public:
|
||||
CustomDiagDesc(diag::Severity DefaultSeverity, std::string Description,
|
||||
unsigned Class = CLASS_WARNING,
|
||||
bool ShowInSystemHeader = false,
|
||||
bool ShowInSystemMacro = false,
|
||||
std::optional<diag::Group> Group = std::nullopt)
|
||||
: DefaultSeverity(static_cast<unsigned>(DefaultSeverity)),
|
||||
DiagClass(Class), ShowInSystemHeader(ShowInSystemHeader),
|
||||
ShowInSystemMacro(ShowInSystemMacro), HasGroup(Group != std::nullopt),
|
||||
Group(Group.value_or(diag::Group{})),
|
||||
Description(std::move(Description)) {}
|
||||
|
||||
std::optional<diag::Group> GetGroup() const {
|
||||
if (HasGroup)
|
||||
return Group;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
diag::Severity GetDefaultSeverity() const {
|
||||
return static_cast<diag::Severity>(DefaultSeverity);
|
||||
}
|
||||
|
||||
Class GetClass() const { return static_cast<Class>(DiagClass); }
|
||||
std::string_view GetDescription() const { return Description; }
|
||||
bool ShouldShowInSystemHeader() const { return ShowInSystemHeader; }
|
||||
|
||||
friend bool operator==(const CustomDiagDesc &lhs,
|
||||
const CustomDiagDesc &rhs) {
|
||||
return lhs.get_as_tuple() == rhs.get_as_tuple();
|
||||
}
|
||||
|
||||
friend bool operator<(const CustomDiagDesc &lhs,
|
||||
const CustomDiagDesc &rhs) {
|
||||
return lhs.get_as_tuple() < rhs.get_as_tuple();
|
||||
}
|
||||
};
|
||||
|
||||
struct GroupInfo {
|
||||
LLVM_PREFERRED_TYPE(diag::Severity)
|
||||
unsigned Severity : 3;
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned HasNoWarningAsError : 1;
|
||||
};
|
||||
|
||||
private:
|
||||
/// Information for uniquing and looking up custom diags.
|
||||
std::unique_ptr<diag::CustomDiagInfo> CustomDiagInfo;
|
||||
std::unique_ptr<GroupInfo[]> GroupInfos = []() {
|
||||
auto GIs = std::make_unique<GroupInfo[]>(
|
||||
static_cast<size_t>(diag::Group::NUM_GROUPS));
|
||||
for (size_t i = 0; i != static_cast<size_t>(diag::Group::NUM_GROUPS); ++i)
|
||||
GIs[i] = {{}, false};
|
||||
return GIs;
|
||||
}();
|
||||
|
||||
public:
|
||||
DiagnosticIDs();
|
||||
@ -202,7 +286,35 @@ public:
|
||||
// FIXME: Replace this function with a create-only facilty like
|
||||
// createCustomDiagIDFromFormatString() to enforce safe usage. At the time of
|
||||
// writing, nearly all callers of this function were invalid.
|
||||
unsigned getCustomDiagID(Level L, StringRef FormatString);
|
||||
unsigned getCustomDiagID(CustomDiagDesc Diag);
|
||||
|
||||
// TODO: Deprecate this once all uses are removed from LLVM
|
||||
// [[deprecated("Use a CustomDiagDesc instead of a Level")]]
|
||||
unsigned getCustomDiagID(Level Level, StringRef Message) {
|
||||
return getCustomDiagID([&]() -> CustomDiagDesc {
|
||||
switch (Level) {
|
||||
case DiagnosticIDs::Level::Ignored:
|
||||
return {diag::Severity::Ignored, std::string(Message), CLASS_WARNING,
|
||||
/*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
|
||||
case DiagnosticIDs::Level::Note:
|
||||
return {diag::Severity::Fatal, std::string(Message), CLASS_NOTE,
|
||||
/*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
|
||||
case DiagnosticIDs::Level::Remark:
|
||||
return {diag::Severity::Remark, std::string(Message), CLASS_REMARK,
|
||||
/*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
|
||||
case DiagnosticIDs::Level::Warning:
|
||||
return {diag::Severity::Warning, std::string(Message), CLASS_WARNING,
|
||||
/*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
|
||||
case DiagnosticIDs::Level::Error:
|
||||
return {diag::Severity::Error, std::string(Message), CLASS_ERROR,
|
||||
/*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
|
||||
case DiagnosticIDs::Level::Fatal:
|
||||
return {diag::Severity::Fatal, std::string(Message), CLASS_ERROR,
|
||||
/*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
|
||||
}
|
||||
llvm_unreachable("Fully covered switch above!");
|
||||
}());
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
@ -214,35 +326,36 @@ public:
|
||||
/// Return true if the unmapped diagnostic levelof the specified
|
||||
/// diagnostic ID is a Warning or Extension.
|
||||
///
|
||||
/// This only works on builtin diagnostics, not custom ones, and is not
|
||||
/// legal to call on NOTEs.
|
||||
static bool isBuiltinWarningOrExtension(unsigned DiagID);
|
||||
/// This is not legal to call on NOTEs.
|
||||
bool isWarningOrExtension(unsigned DiagID) const;
|
||||
|
||||
/// Return true if the specified diagnostic is mapped to errors by
|
||||
/// default.
|
||||
static bool isDefaultMappingAsError(unsigned DiagID);
|
||||
bool isDefaultMappingAsError(unsigned DiagID) const;
|
||||
|
||||
/// Get the default mapping for this diagnostic.
|
||||
static DiagnosticMapping getDefaultMapping(unsigned DiagID);
|
||||
DiagnosticMapping getDefaultMapping(unsigned DiagID) const;
|
||||
|
||||
/// Determine whether the given built-in diagnostic ID is a Note.
|
||||
static bool isBuiltinNote(unsigned DiagID);
|
||||
void initCustomDiagMapping(DiagnosticMapping &, unsigned DiagID);
|
||||
|
||||
/// Determine whether the given built-in diagnostic ID is for an
|
||||
/// Determine whether the given diagnostic ID is a Note.
|
||||
bool isNote(unsigned DiagID) const;
|
||||
|
||||
/// Determine whether the given diagnostic ID is for an
|
||||
/// extension of some sort.
|
||||
static bool isBuiltinExtensionDiag(unsigned DiagID) {
|
||||
bool isExtensionDiag(unsigned DiagID) const {
|
||||
bool ignored;
|
||||
return isBuiltinExtensionDiag(DiagID, ignored);
|
||||
return isExtensionDiag(DiagID, ignored);
|
||||
}
|
||||
|
||||
/// Determine whether the given built-in diagnostic ID is for an
|
||||
/// Determine whether the given diagnostic ID is for an
|
||||
/// extension of some sort, and whether it is enabled by default.
|
||||
///
|
||||
/// This also returns EnabledByDefault, which is set to indicate whether the
|
||||
/// diagnostic is ignored by default (in which case -pedantic enables it) or
|
||||
/// treated as a warning/error by default.
|
||||
///
|
||||
static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault);
|
||||
bool isExtensionDiag(unsigned DiagID, bool &EnabledByDefault) const;
|
||||
|
||||
/// Given a group ID, returns the flag that toggles the group.
|
||||
/// For example, for Group::DeprecatedDeclarations, returns
|
||||
@ -252,19 +365,22 @@ public:
|
||||
/// Given a diagnostic group ID, return its documentation.
|
||||
static StringRef getWarningOptionDocumentation(diag::Group GroupID);
|
||||
|
||||
void setGroupSeverity(StringRef Group, diag::Severity);
|
||||
void setGroupNoWarningsAsError(StringRef Group, bool);
|
||||
|
||||
/// Given a group ID, returns the flag that toggles the group.
|
||||
/// For example, for "deprecated-declarations", returns
|
||||
/// Group::DeprecatedDeclarations.
|
||||
static std::optional<diag::Group> getGroupForWarningOption(StringRef);
|
||||
|
||||
/// Return the lowest-level group that contains the specified diagnostic.
|
||||
static std::optional<diag::Group> getGroupForDiag(unsigned DiagID);
|
||||
std::optional<diag::Group> getGroupForDiag(unsigned DiagID) const;
|
||||
|
||||
/// Return the lowest-level warning option that enables the specified
|
||||
/// diagnostic.
|
||||
///
|
||||
/// If there is no -Wfoo flag that controls the diagnostic, this returns null.
|
||||
static StringRef getWarningOptionForDiag(unsigned DiagID);
|
||||
StringRef getWarningOptionForDiag(unsigned DiagID);
|
||||
|
||||
/// Return the category number that a specified \p DiagID belongs to,
|
||||
/// or 0 if no category.
|
||||
@ -365,6 +481,8 @@ private:
|
||||
getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
const DiagnosticsEngine &Diag) const LLVM_READONLY;
|
||||
|
||||
Class getDiagClass(unsigned DiagID) const;
|
||||
|
||||
/// Used to report a diagnostic that is finally fully formed.
|
||||
///
|
||||
/// \returns \c true if the diagnostic was emitted, \c false if it was
|
||||
|
@ -2953,9 +2953,15 @@ def ext_constexpr_function_never_constant_expr : ExtWarn<
|
||||
"constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
|
||||
def err_attr_cond_never_constant_expr : Error<
|
||||
"%0 attribute expression never produces a constant expression">;
|
||||
def err_diagnose_if_unknown_warning : Error<"unknown warning group '%0'">;
|
||||
def err_diagnose_if_invalid_diagnostic_type : Error<
|
||||
"invalid diagnostic type for 'diagnose_if'; use \"error\" or \"warning\" "
|
||||
"instead">;
|
||||
def err_diagnose_if_unknown_option : Error<"unknown diagnostic option">;
|
||||
def err_diagnose_if_expected_equals : Error<
|
||||
"expected '=' after diagnostic option">;
|
||||
def err_diagnose_if_unexpected_value : Error<
|
||||
"unexpected value; use 'true' or 'false'">;
|
||||
def err_constexpr_body_no_return : Error<
|
||||
"no return statement in %select{constexpr|consteval}0 function">;
|
||||
def err_constexpr_return_missing_expr : Error<
|
||||
|
@ -145,7 +145,7 @@ void DiagnosticsEngine::Reset(bool soft /*=false*/) {
|
||||
|
||||
// Create a DiagState and DiagStatePoint representing diagnostic changes
|
||||
// through command-line.
|
||||
DiagStates.emplace_back();
|
||||
DiagStates.emplace_back(*Diags);
|
||||
DiagStatesByLoc.appendFirst(&DiagStates.back());
|
||||
}
|
||||
}
|
||||
@ -156,8 +156,11 @@ DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
|
||||
DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
|
||||
|
||||
// Initialize the entry if we added it.
|
||||
if (Result.second)
|
||||
Result.first->second = DiagnosticIDs::getDefaultMapping(Diag);
|
||||
if (Result.second) {
|
||||
Result.first->second = DiagIDs.getDefaultMapping(Diag);
|
||||
if (DiagnosticIDs::IsCustomDiag(Diag))
|
||||
DiagIDs.initCustomDiagMapping(Result.first->second, Diag);
|
||||
}
|
||||
|
||||
return Result.first->second;
|
||||
}
|
||||
@ -299,7 +302,8 @@ void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,
|
||||
|
||||
for (auto &Mapping : *Transition.State) {
|
||||
StringRef Option =
|
||||
DiagnosticIDs::getWarningOptionForDiag(Mapping.first);
|
||||
SrcMgr.getDiagnostics().Diags->getWarningOptionForDiag(
|
||||
Mapping.first);
|
||||
if (!DiagName.empty() && DiagName != Option)
|
||||
continue;
|
||||
|
||||
@ -343,9 +347,7 @@ void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
|
||||
|
||||
void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
|
||||
SourceLocation L) {
|
||||
assert(Diag < diag::DIAG_UPPER_LIMIT &&
|
||||
"Can only map builtin diagnostics");
|
||||
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
|
||||
assert((Diags->isWarningOrExtension(Diag) ||
|
||||
(Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
|
||||
"Cannot map errors into warnings!");
|
||||
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
|
||||
@ -397,6 +399,8 @@ bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
|
||||
if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
|
||||
return true;
|
||||
|
||||
Diags->setGroupSeverity(Group, Map);
|
||||
|
||||
// Set the mapping.
|
||||
for (diag::kind Diag : GroupDiags)
|
||||
setSeverity(Diag, Map, Loc);
|
||||
@ -419,6 +423,7 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
|
||||
if (Enabled)
|
||||
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
|
||||
diag::Severity::Error);
|
||||
Diags->setGroupSeverity(Group, diag::Severity::Warning);
|
||||
|
||||
// Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
|
||||
// potentially downgrade anything already mapped to be a warning.
|
||||
@ -450,6 +455,7 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
|
||||
if (Enabled)
|
||||
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
|
||||
diag::Severity::Fatal);
|
||||
Diags->setGroupSeverity(Group, diag::Severity::Error);
|
||||
|
||||
// Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
|
||||
// and potentially downgrade anything already mapped to be a fatal error.
|
||||
@ -482,7 +488,7 @@ void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
|
||||
|
||||
// Set the mapping.
|
||||
for (diag::kind Diag : AllDiags)
|
||||
if (Diags->isBuiltinWarningOrExtension(Diag))
|
||||
if (Diags->isWarningOrExtension(Diag))
|
||||
setSeverity(Diag, Map, Loc);
|
||||
}
|
||||
|
||||
|
@ -62,13 +62,12 @@ const uint32_t StaticDiagInfoDescriptionOffsets[] = {
|
||||
#undef DIAG
|
||||
};
|
||||
|
||||
// Diagnostic classes.
|
||||
enum DiagnosticClass {
|
||||
CLASS_NOTE = 0x01,
|
||||
CLASS_REMARK = 0x02,
|
||||
CLASS_WARNING = 0x03,
|
||||
CLASS_EXTENSION = 0x04,
|
||||
CLASS_ERROR = 0x05
|
||||
CLASS_NOTE = DiagnosticIDs::CLASS_NOTE,
|
||||
CLASS_REMARK = DiagnosticIDs::CLASS_REMARK,
|
||||
CLASS_WARNING = DiagnosticIDs::CLASS_WARNING,
|
||||
CLASS_EXTENSION = DiagnosticIDs::CLASS_EXTENSION,
|
||||
CLASS_ERROR = DiagnosticIDs::CLASS_ERROR,
|
||||
};
|
||||
|
||||
struct StaticDiagInfoRec {
|
||||
@ -229,11 +228,60 @@ CATEGORY(INSTALLAPI, REFACTORING)
|
||||
return Found;
|
||||
}
|
||||
|
||||
DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Custom Diagnostic information
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
using CustomDiagDesc = DiagnosticIDs::CustomDiagDesc;
|
||||
class CustomDiagInfo {
|
||||
std::vector<CustomDiagDesc> DiagInfo;
|
||||
std::map<CustomDiagDesc, unsigned> DiagIDs;
|
||||
std::map<diag::Group, std::vector<unsigned>> GroupToDiags;
|
||||
|
||||
public:
|
||||
/// getDescription - Return the description of the specified custom
|
||||
/// diagnostic.
|
||||
const CustomDiagDesc &getDescription(unsigned DiagID) const {
|
||||
assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
|
||||
"Invalid diagnostic ID");
|
||||
return DiagInfo[DiagID - DIAG_UPPER_LIMIT];
|
||||
}
|
||||
|
||||
unsigned getOrCreateDiagID(DiagnosticIDs::CustomDiagDesc D) {
|
||||
// Check to see if it already exists.
|
||||
std::map<CustomDiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
|
||||
if (I != DiagIDs.end() && I->first == D)
|
||||
return I->second;
|
||||
|
||||
// If not, assign a new ID.
|
||||
unsigned ID = DiagInfo.size() + DIAG_UPPER_LIMIT;
|
||||
DiagIDs.insert(std::make_pair(D, ID));
|
||||
DiagInfo.push_back(D);
|
||||
if (auto Group = D.GetGroup())
|
||||
GroupToDiags[*Group].emplace_back(ID);
|
||||
return ID;
|
||||
}
|
||||
|
||||
ArrayRef<unsigned> getDiagsInGroup(diag::Group G) const {
|
||||
if (auto Diags = GroupToDiags.find(G); Diags != GroupToDiags.end())
|
||||
return Diags->second;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace diag
|
||||
} // namespace clang
|
||||
|
||||
DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) const {
|
||||
DiagnosticMapping Info = DiagnosticMapping::Make(
|
||||
diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
|
||||
|
||||
if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
|
||||
if (IsCustomDiag(DiagID)) {
|
||||
Info.setSeverity(
|
||||
CustomDiagInfo->getDescription(DiagID).GetDefaultSeverity());
|
||||
} else if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
|
||||
Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
|
||||
|
||||
if (StaticInfo->WarnNoWerror) {
|
||||
@ -246,6 +294,22 @@ DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) {
|
||||
return Info;
|
||||
}
|
||||
|
||||
void DiagnosticIDs::initCustomDiagMapping(DiagnosticMapping &Mapping,
|
||||
unsigned DiagID) {
|
||||
assert(IsCustomDiag(DiagID));
|
||||
const auto &Diag = CustomDiagInfo->getDescription(DiagID);
|
||||
if (auto Group = Diag.GetGroup()) {
|
||||
GroupInfo GroupInfo = GroupInfos[static_cast<size_t>(*Group)];
|
||||
if (static_cast<diag::Severity>(GroupInfo.Severity) != diag::Severity())
|
||||
Mapping.setSeverity(static_cast<diag::Severity>(GroupInfo.Severity));
|
||||
Mapping.setNoWarningAsError(GroupInfo.HasNoWarningAsError);
|
||||
} else {
|
||||
Mapping.setSeverity(Diag.GetDefaultSeverity());
|
||||
Mapping.setNoWarningAsError(true);
|
||||
Mapping.setNoErrorAsFatal(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// getCategoryNumberForDiag - Return the category number that a specified
|
||||
/// DiagID belongs to, or 0 if no category.
|
||||
unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
|
||||
@ -303,61 +367,6 @@ bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getBuiltinDiagClass - Return the class field of the diagnostic.
|
||||
///
|
||||
static unsigned getBuiltinDiagClass(unsigned DiagID) {
|
||||
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
|
||||
return Info->Class;
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Custom Diagnostic information
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
class CustomDiagInfo {
|
||||
typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
|
||||
std::vector<DiagDesc> DiagInfo;
|
||||
std::map<DiagDesc, unsigned> DiagIDs;
|
||||
public:
|
||||
|
||||
/// getDescription - Return the description of the specified custom
|
||||
/// diagnostic.
|
||||
StringRef getDescription(unsigned DiagID) const {
|
||||
assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
|
||||
"Invalid diagnostic ID");
|
||||
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
|
||||
}
|
||||
|
||||
/// getLevel - Return the level of the specified custom diagnostic.
|
||||
DiagnosticIDs::Level getLevel(unsigned DiagID) const {
|
||||
assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
|
||||
"Invalid diagnostic ID");
|
||||
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
|
||||
}
|
||||
|
||||
unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
|
||||
DiagnosticIDs &Diags) {
|
||||
DiagDesc D(L, std::string(Message));
|
||||
// Check to see if it already exists.
|
||||
std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
|
||||
if (I != DiagIDs.end() && I->first == D)
|
||||
return I->second;
|
||||
|
||||
// If not, assign a new ID.
|
||||
unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
|
||||
DiagIDs.insert(std::make_pair(D, ID));
|
||||
DiagInfo.push_back(D);
|
||||
return ID;
|
||||
}
|
||||
};
|
||||
|
||||
} // end diag namespace
|
||||
} // end clang namespace
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common Diagnostic implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -372,38 +381,32 @@ DiagnosticIDs::~DiagnosticIDs() {}
|
||||
///
|
||||
/// \param FormatString A fixed diagnostic format string that will be hashed and
|
||||
/// mapped to a unique DiagID.
|
||||
unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
|
||||
unsigned DiagnosticIDs::getCustomDiagID(CustomDiagDesc Diag) {
|
||||
if (!CustomDiagInfo)
|
||||
CustomDiagInfo.reset(new diag::CustomDiagInfo());
|
||||
return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
|
||||
return CustomDiagInfo->getOrCreateDiagID(Diag);
|
||||
}
|
||||
|
||||
|
||||
/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
|
||||
/// level of the specified diagnostic ID is a Warning or Extension.
|
||||
/// This only works on builtin diagnostics, not custom ones, and is not legal to
|
||||
/// call on NOTEs.
|
||||
bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
|
||||
return DiagID < diag::DIAG_UPPER_LIMIT &&
|
||||
getBuiltinDiagClass(DiagID) != CLASS_ERROR;
|
||||
bool DiagnosticIDs::isWarningOrExtension(unsigned DiagID) const {
|
||||
return DiagID < diag::DIAG_UPPER_LIMIT
|
||||
? getDiagClass(DiagID) != CLASS_ERROR
|
||||
: CustomDiagInfo->getDescription(DiagID).GetClass() != CLASS_ERROR;
|
||||
}
|
||||
|
||||
/// Determine whether the given built-in diagnostic ID is a
|
||||
/// Note.
|
||||
bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
|
||||
return DiagID < diag::DIAG_UPPER_LIMIT &&
|
||||
getBuiltinDiagClass(DiagID) == CLASS_NOTE;
|
||||
bool DiagnosticIDs::isNote(unsigned DiagID) const {
|
||||
return DiagID < diag::DIAG_UPPER_LIMIT && getDiagClass(DiagID) == CLASS_NOTE;
|
||||
}
|
||||
|
||||
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
|
||||
/// isExtensionDiag - Determine whether the given built-in diagnostic
|
||||
/// ID is for an extension of some sort. This also returns EnabledByDefault,
|
||||
/// which is set to indicate whether the diagnostic is ignored by default (in
|
||||
/// which case -pedantic enables it) or treated as a warning/error by default.
|
||||
///
|
||||
bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
|
||||
bool &EnabledByDefault) {
|
||||
if (DiagID >= diag::DIAG_UPPER_LIMIT ||
|
||||
getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
|
||||
bool DiagnosticIDs::isExtensionDiag(unsigned DiagID,
|
||||
bool &EnabledByDefault) const {
|
||||
if (IsCustomDiag(DiagID) || getDiagClass(DiagID) != CLASS_EXTENSION)
|
||||
return false;
|
||||
|
||||
EnabledByDefault =
|
||||
@ -411,10 +414,7 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
|
||||
if (DiagID >= diag::DIAG_UPPER_LIMIT)
|
||||
return false;
|
||||
|
||||
bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) const {
|
||||
return getDefaultMapping(DiagID).getSeverity() >= diag::Severity::Error;
|
||||
}
|
||||
|
||||
@ -424,7 +424,7 @@ StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
|
||||
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
|
||||
return Info->getDescription();
|
||||
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
|
||||
return CustomDiagInfo->getDescription(DiagID);
|
||||
return CustomDiagInfo->getDescription(DiagID).GetDescription();
|
||||
}
|
||||
|
||||
static DiagnosticIDs::Level toLevel(diag::Severity SV) {
|
||||
@ -449,13 +449,7 @@ static DiagnosticIDs::Level toLevel(diag::Severity SV) {
|
||||
DiagnosticIDs::Level
|
||||
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
|
||||
const DiagnosticsEngine &Diag) const {
|
||||
// Handle custom diagnostics, which cannot be mapped.
|
||||
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
|
||||
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
|
||||
return CustomDiagInfo->getLevel(DiagID);
|
||||
}
|
||||
|
||||
unsigned DiagClass = getBuiltinDiagClass(DiagID);
|
||||
unsigned DiagClass = getDiagClass(DiagID);
|
||||
if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
|
||||
return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
|
||||
}
|
||||
@ -469,7 +463,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
|
||||
diag::Severity
|
||||
DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
const DiagnosticsEngine &Diag) const {
|
||||
assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
|
||||
bool IsCustomDiag = DiagnosticIDs::IsCustomDiag(DiagID);
|
||||
assert(getDiagClass(DiagID) != CLASS_NOTE);
|
||||
|
||||
// Specific non-error diagnostics may be mapped to various levels from ignored
|
||||
// to error. Errors can only be mapped to fatal.
|
||||
@ -477,7 +472,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
|
||||
// Get the mapping information, or compute it lazily.
|
||||
DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
|
||||
DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
|
||||
DiagnosticMapping Mapping = State->getOrAddMapping((diag::kind)DiagID);
|
||||
|
||||
// TODO: Can a null severity really get here?
|
||||
if (Mapping.getSeverity() != diag::Severity())
|
||||
@ -485,14 +480,15 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
|
||||
// Upgrade ignored diagnostics if -Weverything is enabled.
|
||||
if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
|
||||
!Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
|
||||
!Mapping.isUser() &&
|
||||
(IsCustomDiag || getDiagClass(DiagID) != CLASS_REMARK))
|
||||
Result = diag::Severity::Warning;
|
||||
|
||||
// Ignore -pedantic diagnostics inside __extension__ blocks.
|
||||
// (The diagnostics controlled by -pedantic are the extension diagnostics
|
||||
// that are not enabled by default.)
|
||||
bool EnabledByDefault = false;
|
||||
bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
|
||||
bool IsExtensionDiag = isExtensionDiag(DiagID, EnabledByDefault);
|
||||
if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
|
||||
return diag::Severity::Ignored;
|
||||
|
||||
@ -510,10 +506,12 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
// as well as disabling all messages which are currently mapped to Warning
|
||||
// (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
|
||||
// diagnostic.)
|
||||
// FIXME: Should -w be ignored for custom warnings without a group?
|
||||
if (State->IgnoreAllWarnings) {
|
||||
if (Result == diag::Severity::Warning ||
|
||||
if ((!IsCustomDiag || CustomDiagInfo->getDescription(DiagID).GetGroup()) &&
|
||||
(Result == diag::Severity::Warning ||
|
||||
(Result >= diag::Severity::Error &&
|
||||
!isDefaultMappingAsError((diag::kind)DiagID)))
|
||||
!isDefaultMappingAsError((diag::kind)DiagID))))
|
||||
return diag::Severity::Ignored;
|
||||
}
|
||||
|
||||
@ -541,9 +539,11 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
return Result;
|
||||
|
||||
const auto &SM = Diag.getSourceManager();
|
||||
// Custom diagnostics always are emitted in system headers.
|
||||
|
||||
bool ShowInSystemHeader =
|
||||
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
|
||||
IsCustomDiag
|
||||
? CustomDiagInfo->getDescription(DiagID).ShouldShowInSystemHeader()
|
||||
: !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
|
||||
|
||||
// If we are in a system header, we ignore it. We look at the diagnostic class
|
||||
// because we also want to ignore extensions and warnings in -Werror and
|
||||
@ -566,6 +566,15 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
|
||||
return Result;
|
||||
}
|
||||
|
||||
DiagnosticIDs::Class DiagnosticIDs::getDiagClass(unsigned DiagID) const {
|
||||
if (IsCustomDiag(DiagID))
|
||||
return Class(CustomDiagInfo->getDescription(DiagID).GetClass());
|
||||
|
||||
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
|
||||
return Class(Info->Class);
|
||||
return CLASS_INVALID;
|
||||
}
|
||||
|
||||
#define GET_DIAG_ARRAYS
|
||||
#include "clang/Basic/DiagnosticGroups.inc"
|
||||
#undef GET_DIAG_ARRAYS
|
||||
@ -607,7 +616,12 @@ DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
|
||||
return static_cast<diag::Group>(Found - OptionTable);
|
||||
}
|
||||
|
||||
std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
|
||||
std::optional<diag::Group>
|
||||
DiagnosticIDs::getGroupForDiag(unsigned DiagID) const {
|
||||
if (IsCustomDiag(DiagID)) {
|
||||
assert(CustomDiagInfo);
|
||||
return CustomDiagInfo->getDescription(DiagID).GetGroup();
|
||||
}
|
||||
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
|
||||
return static_cast<diag::Group>(Info->getOptionGroupIndex());
|
||||
return std::nullopt;
|
||||
@ -639,7 +653,8 @@ std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
|
||||
/// were filtered out due to having the wrong flavor.
|
||||
static bool getDiagnosticsInGroup(diag::Flavor Flavor,
|
||||
const WarningOption *Group,
|
||||
SmallVectorImpl<diag::kind> &Diags) {
|
||||
SmallVectorImpl<diag::kind> &Diags,
|
||||
diag::CustomDiagInfo *CustomDiagInfo) {
|
||||
// An empty group is considered to be a warning group: we have empty groups
|
||||
// for GCC compatibility, and GCC does not have remarks.
|
||||
if (!Group->Members && !Group->SubGroups)
|
||||
@ -658,9 +673,14 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor,
|
||||
|
||||
// Add the members of the subgroups.
|
||||
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
|
||||
for (; *SubGroups != (int16_t)-1; ++SubGroups)
|
||||
for (; *SubGroups != (int16_t)-1; ++SubGroups) {
|
||||
if (CustomDiagInfo)
|
||||
llvm::copy(
|
||||
CustomDiagInfo->getDiagsInGroup(static_cast<diag::Group>(*SubGroups)),
|
||||
std::back_inserter(Diags));
|
||||
NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
|
||||
Diags);
|
||||
Diags, CustomDiagInfo);
|
||||
}
|
||||
|
||||
return NotFound;
|
||||
}
|
||||
@ -668,12 +688,49 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor,
|
||||
bool
|
||||
DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
|
||||
SmallVectorImpl<diag::kind> &Diags) const {
|
||||
if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
|
||||
return ::getDiagnosticsInGroup(
|
||||
Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
|
||||
if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
|
||||
if (CustomDiagInfo)
|
||||
llvm::copy(CustomDiagInfo->getDiagsInGroup(*G),
|
||||
std::back_inserter(Diags));
|
||||
return ::getDiagnosticsInGroup(Flavor,
|
||||
&OptionTable[static_cast<unsigned>(*G)],
|
||||
Diags, CustomDiagInfo.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Func>
|
||||
static void forEachSubGroupImpl(const WarningOption *Group, Func func) {
|
||||
for (const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
|
||||
*SubGroups != -1; ++SubGroups) {
|
||||
func(static_cast<size_t>(*SubGroups));
|
||||
forEachSubGroupImpl(&OptionTable[*SubGroups], std::move(func));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Func>
|
||||
static void forEachSubGroup(diag::Group Group, Func func) {
|
||||
const WarningOption *WarningOpt = &OptionTable[static_cast<size_t>(Group)];
|
||||
func(static_cast<size_t>(Group));
|
||||
::forEachSubGroupImpl(WarningOpt, std::move(func));
|
||||
}
|
||||
|
||||
void DiagnosticIDs::setGroupSeverity(StringRef Group, diag::Severity Sev) {
|
||||
if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
|
||||
::forEachSubGroup(*G, [&](size_t SubGroup) {
|
||||
GroupInfos[SubGroup].Severity = static_cast<unsigned>(Sev);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticIDs::setGroupNoWarningsAsError(StringRef Group, bool Val) {
|
||||
if (std::optional<diag::Group> G = getGroupForWarningOption(Group)) {
|
||||
::forEachSubGroup(*G, [&](size_t SubGroup) {
|
||||
GroupInfos[static_cast<size_t>(*G)].HasNoWarningAsError = Val;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
|
||||
std::vector<diag::kind> &Diags) {
|
||||
for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
|
||||
@ -696,7 +753,7 @@ StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
|
||||
|
||||
// Don't suggest groups that are not of this kind.
|
||||
llvm::SmallVector<diag::kind, 8> Diags;
|
||||
if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
|
||||
if (::getDiagnosticsInGroup(Flavor, &O, Diags, nullptr) || Diags.empty())
|
||||
continue;
|
||||
|
||||
if (Distance == BestDistance) {
|
||||
@ -810,14 +867,8 @@ void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag,
|
||||
}
|
||||
|
||||
bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
|
||||
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
|
||||
assert(CustomDiagInfo && "Invalid CustomDiagInfo");
|
||||
// Custom diagnostics.
|
||||
return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
|
||||
}
|
||||
|
||||
// Only errors may be unrecoverable.
|
||||
if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
|
||||
if (getDiagClass(DiagID) < CLASS_ERROR)
|
||||
return false;
|
||||
|
||||
if (DiagID == diag::err_unavailable ||
|
||||
|
@ -129,7 +129,8 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
|
||||
DE.DiagnosticLevel = Level;
|
||||
|
||||
DE.WarningOption =
|
||||
std::string(DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID));
|
||||
std::string(Info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
|
||||
DE.DiagnosticID));
|
||||
|
||||
// Format the message.
|
||||
SmallString<100> MessageStr;
|
||||
@ -160,4 +161,3 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
|
||||
// Record the diagnostic entry.
|
||||
Entries.push_back(DE);
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ private:
|
||||
|
||||
/// Emit the string information for diagnostic flags.
|
||||
unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
|
||||
unsigned DiagID = 0);
|
||||
const Diagnostic *Diag = nullptr);
|
||||
|
||||
unsigned getEmitDiagnosticFlag(StringRef DiagName);
|
||||
|
||||
@ -536,11 +536,13 @@ unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
|
||||
}
|
||||
|
||||
unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
|
||||
unsigned DiagID) {
|
||||
if (DiagLevel == DiagnosticsEngine::Note)
|
||||
const Diagnostic *Diag) {
|
||||
if (!Diag || DiagLevel == DiagnosticsEngine::Note)
|
||||
return 0; // No flag for notes.
|
||||
|
||||
StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
|
||||
StringRef FlagName =
|
||||
Diag->getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
|
||||
Diag->getID());
|
||||
return getEmitDiagnosticFlag(FlagName);
|
||||
}
|
||||
|
||||
@ -655,7 +657,7 @@ void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
|
||||
unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
|
||||
Record.push_back(getEmitCategory(DiagID));
|
||||
// Emit the diagnostic flag string lazily and get the mapped ID.
|
||||
Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
|
||||
Record.push_back(getEmitDiagnosticFlag(Level, Info));
|
||||
} else {
|
||||
Record.push_back(getEmitCategory());
|
||||
Record.push_back(getEmitDiagnosticFlag(Level));
|
||||
|
@ -70,13 +70,17 @@ static void printDiagnosticOptions(raw_ostream &OS,
|
||||
// flag it as such. Note that diagnostics could also have been mapped by a
|
||||
// pragma, but we don't currently have a way to distinguish this.
|
||||
if (Level == DiagnosticsEngine::Error &&
|
||||
DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) &&
|
||||
!DiagnosticIDs::isDefaultMappingAsError(Info.getID())) {
|
||||
Info.getDiags()->getDiagnosticIDs()->isWarningOrExtension(
|
||||
Info.getID()) &&
|
||||
!Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError(
|
||||
Info.getID())) {
|
||||
OS << " [-Werror";
|
||||
Started = true;
|
||||
}
|
||||
|
||||
StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
|
||||
StringRef Opt =
|
||||
Info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
|
||||
Info.getID());
|
||||
if (!Opt.empty()) {
|
||||
OS << (Started ? "," : " [")
|
||||
<< (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt;
|
||||
|
@ -1679,7 +1679,7 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
|
||||
// that is different from the last template instantiation where
|
||||
// we emitted an error, print a template instantiation
|
||||
// backtrace.
|
||||
if (!DiagnosticIDs::isBuiltinNote(DiagID))
|
||||
if (!Diags.getDiagnosticIDs()->isNote(DiagID))
|
||||
PrintContextStack();
|
||||
}
|
||||
|
||||
@ -1693,7 +1693,8 @@ bool Sema::hasUncompilableErrorOccurred() const {
|
||||
if (Loc == DeviceDeferredDiags.end())
|
||||
return false;
|
||||
for (auto PDAt : Loc->second) {
|
||||
if (DiagnosticIDs::isDefaultMappingAsError(PDAt.second.getDiagID()))
|
||||
if (Diags.getDiagnosticIDs()->isDefaultMappingAsError(
|
||||
PDAt.second.getDiagID()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -833,7 +833,7 @@ SemaBase::SemaDiagnosticBuilder SemaCUDA::DiagIfDeviceCode(SourceLocation Loc,
|
||||
if (!getLangOpts().CUDAIsDevice)
|
||||
return SemaDiagnosticBuilder::K_Nop;
|
||||
if (SemaRef.IsLastErrorImmediate &&
|
||||
getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID))
|
||||
getDiagnostics().getDiagnosticIDs()->isNote(DiagID))
|
||||
return SemaDiagnosticBuilder::K_Immediate;
|
||||
return (SemaRef.getEmissionStatus(CurFunContext) ==
|
||||
Sema::FunctionEmissionStatus::Emitted)
|
||||
@ -864,7 +864,7 @@ Sema::SemaDiagnosticBuilder SemaCUDA::DiagIfHostCode(SourceLocation Loc,
|
||||
if (getLangOpts().CUDAIsDevice)
|
||||
return SemaDiagnosticBuilder::K_Nop;
|
||||
if (SemaRef.IsLastErrorImmediate &&
|
||||
getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID))
|
||||
getDiagnostics().getDiagnosticIDs()->isNote(DiagID))
|
||||
return SemaDiagnosticBuilder::K_Immediate;
|
||||
return (SemaRef.getEmissionStatus(CurFunContext) ==
|
||||
Sema::FunctionEmissionStatus::Emitted)
|
||||
|
@ -879,22 +879,38 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg))
|
||||
return;
|
||||
|
||||
StringRef DiagTypeStr;
|
||||
if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr))
|
||||
StringRef DefaultSevStr;
|
||||
if (!S.checkStringLiteralArgumentAttr(AL, 2, DefaultSevStr))
|
||||
return;
|
||||
|
||||
DiagnoseIfAttr::DiagnosticType DiagType;
|
||||
if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) {
|
||||
DiagnoseIfAttr::DefaultSeverity DefaultSev;
|
||||
if (!DiagnoseIfAttr::ConvertStrToDefaultSeverity(DefaultSevStr, DefaultSev)) {
|
||||
S.Diag(AL.getArgAsExpr(2)->getBeginLoc(),
|
||||
diag::err_diagnose_if_invalid_diagnostic_type);
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef WarningGroup;
|
||||
SmallVector<StringRef, 2> Options;
|
||||
if (AL.getNumArgs() > 3) {
|
||||
if (!S.checkStringLiteralArgumentAttr(AL, 3, WarningGroup))
|
||||
return;
|
||||
if (WarningGroup.empty() ||
|
||||
!S.getDiagnostics().getDiagnosticIDs()->getGroupForWarningOption(
|
||||
WarningGroup)) {
|
||||
S.Diag(AL.getArgAsExpr(3)->getBeginLoc(),
|
||||
diag::err_diagnose_if_unknown_warning)
|
||||
<< WarningGroup;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool ArgDependent = false;
|
||||
if (const auto *FD = dyn_cast<FunctionDecl>(D))
|
||||
ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
|
||||
D->addAttr(::new (S.Context) DiagnoseIfAttr(
|
||||
S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
|
||||
S.Context, AL, Cond, Msg, DefaultSev, WarningGroup, ArgDependent,
|
||||
cast<NamedDecl>(D)));
|
||||
}
|
||||
|
||||
static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
|
@ -7377,8 +7377,10 @@ static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
|
||||
return false;
|
||||
|
||||
auto WarningBegin = std::stable_partition(
|
||||
Attrs.begin(), Attrs.end(),
|
||||
[](const DiagnoseIfAttr *DIA) { return DIA->isError(); });
|
||||
Attrs.begin(), Attrs.end(), [](const DiagnoseIfAttr *DIA) {
|
||||
return DIA->getDefaultSeverity() == DiagnoseIfAttr::DS_error &&
|
||||
DIA->getWarningGroup().empty();
|
||||
});
|
||||
|
||||
// Note that diagnose_if attributes are late-parsed, so they appear in the
|
||||
// correct order (unlike enable_if attributes).
|
||||
@ -7392,11 +7394,32 @@ static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
|
||||
return true;
|
||||
}
|
||||
|
||||
auto ToSeverity = [](DiagnoseIfAttr::DefaultSeverity Sev) {
|
||||
switch (Sev) {
|
||||
case DiagnoseIfAttr::DS_warning:
|
||||
return diag::Severity::Warning;
|
||||
case DiagnoseIfAttr::DS_error:
|
||||
return diag::Severity::Error;
|
||||
}
|
||||
llvm_unreachable("Fully covered switch above!");
|
||||
};
|
||||
|
||||
for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end()))
|
||||
if (IsSuccessful(DIA)) {
|
||||
if (DIA->getWarningGroup().empty() &&
|
||||
DIA->getDefaultSeverity() == DiagnoseIfAttr::DS_warning) {
|
||||
S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage();
|
||||
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
|
||||
<< DIA->getParent() << DIA->getCond()->getSourceRange();
|
||||
} else {
|
||||
auto DiagGroup = S.Diags.getDiagnosticIDs()->getGroupForWarningOption(
|
||||
DIA->getWarningGroup());
|
||||
assert(DiagGroup);
|
||||
auto DiagID = S.Diags.getDiagnosticIDs()->getCustomDiagID(
|
||||
{ToSeverity(DIA->getDefaultSeverity()), "%0",
|
||||
DiagnosticIDs::CLASS_WARNING, false, false, *DiagGroup});
|
||||
S.Diag(Loc, DiagID) << DIA->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -284,7 +284,8 @@ static void instantiateDependentDiagnoseIfAttr(
|
||||
if (Cond)
|
||||
New->addAttr(new (S.getASTContext()) DiagnoseIfAttr(
|
||||
S.getASTContext(), *DIA, Cond, DIA->getMessage(),
|
||||
DIA->getDiagnosticType(), DIA->getArgDependent(), New));
|
||||
DIA->getDefaultSeverity(), DIA->getWarningGroup(),
|
||||
DIA->getArgDependent(), New));
|
||||
}
|
||||
|
||||
// Constructs and adds to New a new instance of CUDALaunchBoundsAttr using
|
||||
|
@ -6864,7 +6864,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
|
||||
// command line (-w, -Weverything, -Werror, ...) along with any explicit
|
||||
// -Wblah flags.
|
||||
unsigned Flags = Record[Idx++];
|
||||
DiagState Initial;
|
||||
DiagState Initial(*Diag.getDiagnosticIDs());
|
||||
Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;
|
||||
Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;
|
||||
Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;
|
||||
|
@ -3264,7 +3264,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
|
||||
// Skip default mappings. We have a mapping for every diagnostic ever
|
||||
// emitted, regardless of whether it was customized.
|
||||
if (!I.second.isPragma() &&
|
||||
I.second == DiagnosticIDs::getDefaultMapping(I.first))
|
||||
I.second == Diag.getDiagnosticIDs()->getDefaultMapping(I.first))
|
||||
continue;
|
||||
Mappings.push_back(I);
|
||||
}
|
||||
|
@ -91,7 +91,6 @@ public:
|
||||
? " [" + PD->getCheckerName() + "]"
|
||||
: "")
|
||||
.str();
|
||||
|
||||
reportPiece(WarnID, PD->getLocation().asLocation(),
|
||||
(PD->getShortDescription() + WarningMsg).str(),
|
||||
PD->path.back()->getRanges(), PD->path.back()->getFixits());
|
||||
|
9
clang/test/Frontend/custom-diag-werror-interaction.c
Normal file
9
clang/test/Frontend/custom-diag-werror-interaction.c
Normal file
@ -0,0 +1,9 @@
|
||||
// RUN: %clang_cc1 -emit-llvm-only -fprofile-instrument=clang -fcoverage-mcdc -Werror -Wno-unused-value %s -verify
|
||||
|
||||
int foo(int x);
|
||||
|
||||
int main(void) {
|
||||
int a, b, c;
|
||||
a && foo( b && c ); // expected-warning{{unsupported MC/DC boolean expression; contains an operation with a nested boolean expression. Expression will not be covered}}
|
||||
return 0;
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
|
||||
#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
|
||||
|
||||
void failure1(void) _diagnose_if(); // expected-error{{exactly 3 arguments}}
|
||||
void failure2(void) _diagnose_if(0); // expected-error{{exactly 3 arguments}}
|
||||
void failure3(void) _diagnose_if(0, ""); // expected-error{{exactly 3 arguments}}
|
||||
void failure4(void) _diagnose_if(0, "", "error", 1); // expected-error{{exactly 3 arguments}}
|
||||
void failure1(void) _diagnose_if(); // expected-error{{at least 3 arguments}}
|
||||
void failure2(void) _diagnose_if(0); // expected-error{{at least 3 arguments}}
|
||||
void failure3(void) _diagnose_if(0, ""); // expected-error{{at least 3 arguments}}
|
||||
void failure4(void) _diagnose_if(0, "", "error", 1); // expected-error{{expected string literal as argument}}
|
||||
void failure5(void) _diagnose_if(0, 0, "error"); // expected-error{{expected string literal as argument of 'diagnose_if' attribute}}
|
||||
void failure6(void) _diagnose_if(0, "", "invalid"); // expected-error{{invalid diagnostic type for 'diagnose_if'; use "error" or "warning" instead}}
|
||||
void failure7(void) _diagnose_if(0, "", "ERROR"); // expected-error{{invalid diagnostic type}}
|
||||
|
63
clang/test/SemaCXX/diagnose_if-warning-group.cpp
Normal file
63
clang/test/SemaCXX/diagnose_if-warning-group.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
// RUN: %clang_cc1 %s -verify=expected,wall -fno-builtin -Wno-pedantic -Werror=comment -Wno-error=abi -Wfatal-errors=assume -Wno-fatal-errors=assume -Wno-format
|
||||
// RUN: %clang_cc1 %s -verify=expected,wno-all,pedantic,format -fno-builtin -Wno-all -Werror=comment -Wno-error=abi -Werror=assume -Wformat
|
||||
|
||||
#define diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
|
||||
|
||||
#ifndef EMTY_WARNING_GROUP
|
||||
void bougus_warning() diagnose_if(true, "oh no", "warning", "bogus warning") {} // expected-error {{unknown warning group 'bogus warning'}}
|
||||
|
||||
void show_in_system_header() diagnose_if(true, "oh no", "warning", "assume", "Banane") {} // expected-error {{'diagnose_if' attribute takes no more than 4 arguments}}
|
||||
#endif // EMTY_WARNING_GROUP
|
||||
|
||||
template <bool b>
|
||||
void diagnose_if_wcomma() diagnose_if(b, "oh no", "warning", "comma") {}
|
||||
|
||||
template <bool b>
|
||||
void diagnose_if_wcomment() diagnose_if(b, "oh no", "warning", "comment") {}
|
||||
|
||||
void empty_warning_group() diagnose_if(true, "oh no", "warning", "") {} // expected-error {{unknown warning group ''}}
|
||||
void empty_warning_group_error() diagnose_if(true, "oh no", "error", "") {} // expected-error {{unknown warning group ''}}
|
||||
|
||||
void diagnose_if_wabi_default_error() diagnose_if(true, "ABI stuff", "error", "abi") {}
|
||||
void diagnose_assume() diagnose_if(true, "Assume diagnostic", "warning", "assume") {}
|
||||
|
||||
void Wall() diagnose_if(true, "oh no", "warning", "all") {}
|
||||
void Wpedantic() diagnose_if(true, "oh no", "warning", "pedantic") {}
|
||||
void Wformat_extra_args() diagnose_if(true, "oh no", "warning", "format-extra-args") {}
|
||||
|
||||
void call() {
|
||||
diagnose_if_wcomma<true>(); // expected-warning {{oh no}}
|
||||
diagnose_if_wcomma<false>();
|
||||
diagnose_if_wcomment<true>(); // expected-error {{oh no}}
|
||||
diagnose_if_wcomment<false>();
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcomma"
|
||||
diagnose_if_wcomma<true>();
|
||||
diagnose_if_wcomment<true>(); // expected-error {{oh no}}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcomment"
|
||||
diagnose_if_wcomma<true>(); // expected-warning {{oh no}}
|
||||
diagnose_if_wcomment<true>();
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
diagnose_if_wcomma<true>(); // expected-warning {{oh no}}
|
||||
diagnose_if_wcomment<true>(); // expected-error {{oh no}}
|
||||
|
||||
diagnose_if_wabi_default_error(); // expected-warning {{ABI stuff}}
|
||||
diagnose_assume(); // expected-error {{Assume diagnostic}}
|
||||
|
||||
// Make sure that the -Wassume diagnostic isn't fatal
|
||||
diagnose_if_wabi_default_error(); // expected-warning {{ABI stuff}}
|
||||
|
||||
Wall(); // wall-warning {{oh no}}
|
||||
Wpedantic(); // pedantic-warning {{oh no}}
|
||||
Wformat_extra_args(); // format-warning {{oh no}}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wformat"
|
||||
Wformat_extra_args();
|
||||
#pragma clang diagnostic pop
|
||||
}
|
@ -53,13 +53,13 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
|
||||
for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
|
||||
const unsigned diagID = DR.DiagID;
|
||||
|
||||
if (DiagnosticIDs::isBuiltinNote(diagID))
|
||||
if (DiagnosticIDs{}.isNote(diagID))
|
||||
continue;
|
||||
|
||||
if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
|
||||
if (!DiagnosticIDs{}.isWarningOrExtension(diagID))
|
||||
continue;
|
||||
|
||||
Entry entry(DR.getName(), DiagnosticIDs::getWarningOptionForDiag(diagID));
|
||||
Entry entry(DR.getName(), DiagnosticIDs{}.getWarningOptionForDiag(diagID));
|
||||
|
||||
if (entry.Flag.empty())
|
||||
Unflagged.push_back(entry);
|
||||
@ -97,4 +97,3 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -119,10 +119,10 @@ int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
|
||||
for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
|
||||
unsigned DiagID = DR.DiagID;
|
||||
|
||||
if (DiagnosticIDs::isBuiltinNote(DiagID))
|
||||
if (DiagnosticIDs{}.isNote(DiagID))
|
||||
continue;
|
||||
|
||||
if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
|
||||
if (!DiagnosticIDs{}.isWarningOrExtension(DiagID))
|
||||
continue;
|
||||
|
||||
DiagnosticsEngine::Level DiagLevel =
|
||||
@ -130,7 +130,7 @@ int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
|
||||
if (DiagLevel == DiagnosticsEngine::Ignored)
|
||||
continue;
|
||||
|
||||
StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
|
||||
StringRef WarningOpt = DiagnosticIDs{}.getWarningOptionForDiag(DiagID);
|
||||
Active.push_back(PrettyDiag(DR.getName(), WarningOpt, DiagLevel));
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,9 @@ CXString CXStoredDiagnostic::getSpelling() const {
|
||||
|
||||
CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
|
||||
unsigned ID = Diag.getID();
|
||||
StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
|
||||
if (DiagnosticIDs::IsCustomDiag(ID))
|
||||
return cxstring::createEmpty();
|
||||
StringRef Option = DiagnosticIDs{}.getWarningOptionForDiag(ID);
|
||||
if (!Option.empty()) {
|
||||
if (Disable)
|
||||
*Disable = cxstring::createDup((Twine("-Wno-") + Option).str());
|
||||
|
@ -39,7 +39,8 @@ static void printRemarkOption(llvm::raw_ostream &os,
|
||||
clang::DiagnosticsEngine::Level level,
|
||||
const clang::Diagnostic &info) {
|
||||
llvm::StringRef opt =
|
||||
clang::DiagnosticIDs::getWarningOptionForDiag(info.getID());
|
||||
info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
|
||||
info.getID());
|
||||
if (!opt.empty()) {
|
||||
// We still need to check if the level is a Remark since, an unknown option
|
||||
// warning could be printed i.e. [-Wunknown-warning-option]
|
||||
|
Loading…
x
Reference in New Issue
Block a user