mirror of https://github.com/microsoft/clang.git
[Clang Tablegen][RFC] Allow Early Textual Substitutions in `Diagnostic` messages.
Summary: There are cases where the same string or select is repeated verbatim in a lot of diagnostics. This can be a pain to maintain and update. Tablegen provides no way stash the common text somewhere and reuse it in the diagnostics, until now! This patch allows diagnostic texts to contain `%sub{<definition-name>}`, where `<definition-name>` names a Tablegen record of type `TextSubstitution`. These substitutions are done early, before the diagnostic string is otherwise processed. All `%sub` modifiers will be replaced before the diagnostic definitions are emitted. The substitution must specify all arguments used by the substitution, and modifier indexes in the substitution are re-numbered accordingly. For example: ``` def select_ovl_candidate : TextSubstitution<"%select{function|constructor}0%select{| template| %2}1">; ``` when used as ``` "candidate `%sub{select_ovl_candidate}3,2,1 not viable" ``` will act as if we wrote: ``` "candidate %select{function|constructor}3%select{| template| %1}2 not viable" ``` Reviewers: rsmith, rjmccall, aaron.ballman, a.sidorin Reviewed By: rjmccall Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D46740 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332799 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5b04748157
commit
a6a3cf5fce
|
@ -319,6 +319,32 @@ they should be discussed before they are added. If you are creating a lot of
|
||||||
repetitive diagnostics and/or have an idea for a useful formatter, please bring
|
repetitive diagnostics and/or have an idea for a useful formatter, please bring
|
||||||
it up on the cfe-dev mailing list.
|
it up on the cfe-dev mailing list.
|
||||||
|
|
||||||
|
**"sub" format**
|
||||||
|
|
||||||
|
Example:
|
||||||
|
Given the following record definition of type ``TextSubstitution``:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def select_ovl_candidate : TextSubstitution<
|
||||||
|
"%select{function|constructor}0%select{| template| %2}1">;
|
||||||
|
|
||||||
|
which can be used as
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
def note_ovl_candidate : Note<
|
||||||
|
"candidate %sub{select_ovl_candidate}3,2,1 not viable">;
|
||||||
|
|
||||||
|
and will act as if it was written
|
||||||
|
``"candidate %select{function|constructor}3%select{| template| %1}2 not viable"``.
|
||||||
|
Description:
|
||||||
|
This format specifier is used to avoid repeating strings verbatim in multiple
|
||||||
|
diagnostics. The argument to ``%sub`` must name a ``TextSubstitution`` tblgen
|
||||||
|
record. The substitution must specify all arguments used by the substitution,
|
||||||
|
and the modifier indexes in the substitution are re-numbered accordingly. The
|
||||||
|
substituted text must itself be a valid format string before substitution.
|
||||||
|
|
||||||
.. _internals-producing-diag:
|
.. _internals-producing-diag:
|
||||||
|
|
||||||
Producing the Diagnostic
|
Producing the Diagnostic
|
||||||
|
|
|
@ -39,6 +39,15 @@ def SFINAE_Suppress : SFINAEResponse;
|
||||||
def SFINAE_Report : SFINAEResponse;
|
def SFINAE_Report : SFINAEResponse;
|
||||||
def SFINAE_AccessControl : SFINAEResponse;
|
def SFINAE_AccessControl : SFINAEResponse;
|
||||||
|
|
||||||
|
// Textual substitutions which may be performed on the text of diagnostics
|
||||||
|
class TextSubstitution<string Text> {
|
||||||
|
string Substitution = Text;
|
||||||
|
// TODO: These are only here to allow substitutions to be declared inline with
|
||||||
|
// diagnostics
|
||||||
|
string Component = "";
|
||||||
|
string CategoryName = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Diagnostic Categories. These can be applied to groups or individual
|
// Diagnostic Categories. These can be applied to groups or individual
|
||||||
// diagnostics to specify a category.
|
// diagnostics to specify a category.
|
||||||
class DiagCategory<string Name> {
|
class DiagCategory<string Name> {
|
||||||
|
|
|
@ -1622,13 +1622,16 @@ def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning<
|
||||||
"overrides of %0 in subclasses are not available in the "
|
"overrides of %0 in subclasses are not available in the "
|
||||||
"%select{constructor|destructor}1 of %2">;
|
"%select{constructor|destructor}1 of %2">;
|
||||||
|
|
||||||
|
def select_special_member_kind : TextSubstitution<
|
||||||
|
"%select{default constructor|copy constructor|move constructor|"
|
||||||
|
"copy assignment operator|move assignment operator|destructor}0">;
|
||||||
|
|
||||||
def note_member_declared_at : Note<"member is declared here">;
|
def note_member_declared_at : Note<"member is declared here">;
|
||||||
def note_ivar_decl : Note<"instance variable is declared here">;
|
def note_ivar_decl : Note<"instance variable is declared here">;
|
||||||
def note_bitfield_decl : Note<"bit-field is declared here">;
|
def note_bitfield_decl : Note<"bit-field is declared here">;
|
||||||
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
|
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
|
||||||
def note_member_synthesized_at : Note<
|
def note_member_synthesized_at : Note<
|
||||||
"in implicit %select{default constructor|copy constructor|move constructor|"
|
"in implicit %sub{select_special_member_kind}0 for %1 "
|
||||||
"copy assignment operator|move assignment operator|destructor}0 for %1 "
|
|
||||||
"first required here">;
|
"first required here">;
|
||||||
def err_missing_default_ctor : Error<
|
def err_missing_default_ctor : Error<
|
||||||
"%select{constructor for %1 must explicitly initialize the|"
|
"%select{constructor for %1 must explicitly initialize the|"
|
||||||
|
@ -1641,12 +1644,10 @@ def note_due_to_dllexported_class : Note<
|
||||||
|
|
||||||
def err_illegal_union_or_anon_struct_member : Error<
|
def err_illegal_union_or_anon_struct_member : Error<
|
||||||
"%select{anonymous struct|union}0 member %1 has a non-trivial "
|
"%select{anonymous struct|union}0 member %1 has a non-trivial "
|
||||||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
"%sub{select_special_member_kind}2">;
|
||||||
"operator|move assignment operator|destructor}2">;
|
|
||||||
def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
|
def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
|
||||||
"%select{anonymous struct|union}0 member %1 with a non-trivial "
|
"%select{anonymous struct|union}0 member %1 with a non-trivial "
|
||||||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
"%sub{select_special_member_kind}2 is incompatible with C++98">,
|
||||||
"operator|move assignment operator|destructor}2 is incompatible with C++98">,
|
|
||||||
InGroup<CXX98Compat>, DefaultIgnore;
|
InGroup<CXX98Compat>, DefaultIgnore;
|
||||||
|
|
||||||
def note_nontrivial_virtual_dtor : Note<
|
def note_nontrivial_virtual_dtor : Note<
|
||||||
|
@ -1665,8 +1666,7 @@ def note_nontrivial_no_copy : Note<
|
||||||
"%select{base class|field|an object}0 of type %3">;
|
"%select{base class|field|an object}0 of type %3">;
|
||||||
def note_nontrivial_user_provided : Note<
|
def note_nontrivial_user_provided : Note<
|
||||||
"because %select{base class of |field of |}0type %1 has a user-provided "
|
"because %select{base class of |field of |}0type %1 has a user-provided "
|
||||||
"%select{default constructor|copy constructor|move constructor|"
|
"%sub{select_special_member_kind}2">;
|
||||||
"copy assignment operator|move assignment operator|destructor}2">;
|
|
||||||
def note_nontrivial_in_class_init : Note<
|
def note_nontrivial_in_class_init : Note<
|
||||||
"because field %0 has an initializer">;
|
"because field %0 has an initializer">;
|
||||||
def note_nontrivial_param_type : Note<
|
def note_nontrivial_param_type : Note<
|
||||||
|
@ -1733,9 +1733,7 @@ def err_covariant_return_type_class_type_more_qualified : Error<
|
||||||
|
|
||||||
// C++ implicit special member functions
|
// C++ implicit special member functions
|
||||||
def note_in_declaration_of_implicit_special_member : Note<
|
def note_in_declaration_of_implicit_special_member : Note<
|
||||||
"while declaring the implicit "
|
"while declaring the implicit %sub{select_special_member_kind}1"
|
||||||
"%select{default constructor|copy constructor|move constructor|"
|
|
||||||
"copy assignment operator|move assignment operator|destructor}1"
|
|
||||||
" for %0">;
|
" for %0">;
|
||||||
|
|
||||||
// C++ constructors
|
// C++ constructors
|
||||||
|
@ -3837,13 +3835,7 @@ def note_ovl_candidate_bad_target : Note<
|
||||||
"%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from"
|
"%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from"
|
||||||
" %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">;
|
" %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">;
|
||||||
def note_implicit_member_target_infer_collision : Note<
|
def note_implicit_member_target_infer_collision : Note<
|
||||||
"implicit %select{"
|
"implicit %sub{select_special_member_kind}0 inferred target collision: call to both "
|
||||||
"default constructor|"
|
|
||||||
"copy constructor|"
|
|
||||||
"move constructor|"
|
|
||||||
"copy assignment operator|"
|
|
||||||
"move assignment operator|"
|
|
||||||
"destructor}0 inferred target collision: call to both "
|
|
||||||
"%select{__device__|__global__|__host__|__host__ __device__}1 and "
|
"%select{__device__|__global__|__host__|__host__ __device__}1 and "
|
||||||
"%select{__device__|__global__|__host__|__host__ __device__}2 members">;
|
"%select{__device__|__global__|__host__|__host__ __device__}2 members">;
|
||||||
|
|
||||||
|
@ -3885,9 +3877,7 @@ def err_ovl_deleted_oper : Error<
|
||||||
"overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">;
|
"overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">;
|
||||||
def err_ovl_deleted_special_oper : Error<
|
def err_ovl_deleted_special_oper : Error<
|
||||||
"object of type %0 cannot be %select{constructed|copied|moved|assigned|"
|
"object of type %0 cannot be %select{constructed|copied|moved|assigned|"
|
||||||
"assigned|destroyed}1 because its %select{default constructor|"
|
"assigned|destroyed}1 because its %sub{select_special_member_kind}1 is implicitly deleted">;
|
||||||
"copy constructor|move constructor|copy assignment operator|"
|
|
||||||
"move assignment operator|destructor}1 is implicitly deleted">;
|
|
||||||
def err_ovl_no_viable_subscript :
|
def err_ovl_no_viable_subscript :
|
||||||
Error<"no viable overloaded operator[] for type %0">;
|
Error<"no viable overloaded operator[] for type %0">;
|
||||||
def err_ovl_no_oper :
|
def err_ovl_no_oper :
|
||||||
|
@ -7767,9 +7757,8 @@ def err_defaulted_special_member_quals : Error<
|
||||||
"an explicitly-defaulted %select{copy|move}0 assignment operator may not "
|
"an explicitly-defaulted %select{copy|move}0 assignment operator may not "
|
||||||
"have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">;
|
"have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">;
|
||||||
def err_defaulted_special_member_volatile_param : Error<
|
def err_defaulted_special_member_volatile_param : Error<
|
||||||
"the parameter for an explicitly-defaulted %select{<<ERROR>>|"
|
"the parameter for an explicitly-defaulted %sub{select_special_member_kind}0 "
|
||||||
"copy constructor|move constructor|copy assignment operator|"
|
"may not be volatile">;
|
||||||
"move assignment operator|<<ERROR>>}0 may not be volatile">;
|
|
||||||
def err_defaulted_special_member_move_const_param : Error<
|
def err_defaulted_special_member_move_const_param : Error<
|
||||||
"the parameter for an explicitly-defaulted move "
|
"the parameter for an explicitly-defaulted move "
|
||||||
"%select{constructor|assignment operator}0 may not be const">;
|
"%select{constructor|assignment operator}0 may not be const">;
|
||||||
|
@ -7781,17 +7770,13 @@ def err_defaulted_copy_assign_not_ref : Error<
|
||||||
"the parameter for an explicitly-defaulted copy assignment operator must be an "
|
"the parameter for an explicitly-defaulted copy assignment operator must be an "
|
||||||
"lvalue reference type">;
|
"lvalue reference type">;
|
||||||
def err_incorrect_defaulted_exception_spec : Error<
|
def err_incorrect_defaulted_exception_spec : Error<
|
||||||
"exception specification of explicitly defaulted %select{default constructor|"
|
"exception specification of explicitly defaulted "
|
||||||
"copy constructor|move constructor|copy assignment operator|move assignment "
|
"%sub{select_special_member_kind}0 does not match the calculated one">;
|
||||||
"operator|destructor}0 does not match the "
|
|
||||||
"calculated one">;
|
|
||||||
def err_incorrect_defaulted_constexpr : Error<
|
def err_incorrect_defaulted_constexpr : Error<
|
||||||
"defaulted definition of %select{default constructor|copy constructor|"
|
"defaulted definition of %sub{select_special_member_kind}0 "
|
||||||
"move constructor|copy assignment operator|move assignment operator}0 "
|
|
||||||
"is not constexpr">;
|
"is not constexpr">;
|
||||||
def err_out_of_line_default_deletes : Error<
|
def err_out_of_line_default_deletes : Error<
|
||||||
"defaulting this %select{default constructor|copy constructor|move "
|
"defaulting this %sub{select_special_member_kind}0 "
|
||||||
"constructor|copy assignment operator|move assignment operator|destructor}0 "
|
|
||||||
"would delete it after its first declaration">;
|
"would delete it after its first declaration">;
|
||||||
def warn_vbase_moved_multiple_times : Warning<
|
def warn_vbase_moved_multiple_times : Warning<
|
||||||
"defaulted move assignment operator of %0 will move assign virtual base "
|
"defaulted move assignment operator of %0 will move assign virtual base "
|
||||||
|
|
|
@ -16,7 +16,7 @@ struct E {
|
||||||
struct {
|
struct {
|
||||||
S x;
|
S x;
|
||||||
#if __cplusplus <= 199711L
|
#if __cplusplus <= 199711L
|
||||||
// expected-error@-2 {{anonymous struct member 'x' has a non-trivial constructor}}
|
// expected-error@-2 {{anonymous struct member 'x' has a non-trivial default constructor}}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
static struct {
|
static struct {
|
||||||
|
|
|
@ -241,13 +241,13 @@ namespace UnionOrAnonStructMembers {
|
||||||
~NonTrivDtor(); // expected-note 2{{user-provided destructor}}
|
~NonTrivDtor(); // expected-note 2{{user-provided destructor}}
|
||||||
};
|
};
|
||||||
union BadUnion {
|
union BadUnion {
|
||||||
NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial constructor is incompatible with C++98}}
|
NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial default constructor is incompatible with C++98}}
|
||||||
NonTrivCopy ntcp; // expected-warning {{union member 'ntcp' with a non-trivial copy constructor is incompatible with C++98}}
|
NonTrivCopy ntcp; // expected-warning {{union member 'ntcp' with a non-trivial copy constructor is incompatible with C++98}}
|
||||||
NonTrivDtor ntd; // expected-warning {{union member 'ntd' with a non-trivial destructor is incompatible with C++98}}
|
NonTrivDtor ntd; // expected-warning {{union member 'ntd' with a non-trivial destructor is incompatible with C++98}}
|
||||||
};
|
};
|
||||||
struct Wrap {
|
struct Wrap {
|
||||||
struct {
|
struct {
|
||||||
NonTrivCtor ntc; // expected-warning {{anonymous struct member 'ntc' with a non-trivial constructor is incompatible with C++98}}
|
NonTrivCtor ntc; // expected-warning {{anonymous struct member 'ntc' with a non-trivial default constructor is incompatible with C++98}}
|
||||||
NonTrivCopy ntcp; // expected-warning {{anonymous struct member 'ntcp' with a non-trivial copy constructor is incompatible with C++98}}
|
NonTrivCopy ntcp; // expected-warning {{anonymous struct member 'ntcp' with a non-trivial copy constructor is incompatible with C++98}}
|
||||||
NonTrivDtor ntd; // expected-warning {{anonymous struct member 'ntd' with a non-trivial destructor is incompatible with C++98}}
|
NonTrivDtor ntd; // expected-warning {{anonymous struct member 'ntd' with a non-trivial destructor is incompatible with C++98}}
|
||||||
};
|
};
|
||||||
|
@ -348,7 +348,7 @@ namespace rdar11736429 {
|
||||||
};
|
};
|
||||||
|
|
||||||
union S {
|
union S {
|
||||||
X x; // expected-warning{{union member 'x' with a non-trivial constructor is incompatible with C++98}}
|
X x; // expected-warning{{union member 'x' with a non-trivial default constructor is incompatible with C++98}}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,130 @@
|
||||||
// Define the diagnostic mappings.
|
//===--- DiagnosticBase.inc - A test file mimicking Diagnostic.td ---------===//
|
||||||
class DiagMapping;
|
//
|
||||||
def MAP_IGNORE : DiagMapping;
|
// The LLVM Compiler Infrastructure
|
||||||
def MAP_WARNING : DiagMapping;
|
//
|
||||||
def MAP_ERROR : DiagMapping;
|
// This file is distributed under the University of Illinois Open Source
|
||||||
def MAP_FATAL : DiagMapping;
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file defines the TableGen core definitions for the diagnostics
|
||||||
|
// and diagnostic control.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
// See the Internals Manual, section The Diagnostics Subsystem for an overview.
|
||||||
|
|
||||||
|
// Define the diagnostic severities.
|
||||||
|
class Severity<string N> {
|
||||||
|
string Name = N;
|
||||||
|
}
|
||||||
|
def SEV_Ignored : Severity<"Ignored">;
|
||||||
|
def SEV_Remark : Severity<"Remark">;
|
||||||
|
def SEV_Warning : Severity<"Warning">;
|
||||||
|
def SEV_Error : Severity<"Error">;
|
||||||
|
def SEV_Fatal : Severity<"Fatal">;
|
||||||
|
|
||||||
// Define the diagnostic classes.
|
// Define the diagnostic classes.
|
||||||
class DiagClass;
|
class DiagClass;
|
||||||
def CLASS_NOTE : DiagClass;
|
def CLASS_NOTE : DiagClass;
|
||||||
|
def CLASS_REMARK : DiagClass;
|
||||||
def CLASS_WARNING : DiagClass;
|
def CLASS_WARNING : DiagClass;
|
||||||
def CLASS_EXTENSION : DiagClass;
|
def CLASS_EXTENSION : DiagClass;
|
||||||
def CLASS_ERROR : DiagClass;
|
def CLASS_ERROR : DiagClass;
|
||||||
|
|
||||||
|
// Responses to a diagnostic in a SFINAE context.
|
||||||
|
class SFINAEResponse;
|
||||||
|
def SFINAE_SubstitutionFailure : SFINAEResponse;
|
||||||
|
def SFINAE_Suppress : SFINAEResponse;
|
||||||
|
def SFINAE_Report : SFINAEResponse;
|
||||||
|
def SFINAE_AccessControl : SFINAEResponse;
|
||||||
|
|
||||||
|
// Textual substitutions which may be performed on the text of diagnostics
|
||||||
|
class TextSubstitution<string Text> {
|
||||||
|
string Substitution = Text;
|
||||||
|
// TODO: These are only here to allow substitutions to be declared inline with
|
||||||
|
// diagnostics
|
||||||
|
string Component = "";
|
||||||
|
string CategoryName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnostic Categories. These can be applied to groups or individual
|
||||||
|
// diagnostics to specify a category.
|
||||||
|
class DiagCategory<string Name> {
|
||||||
|
string CategoryName = Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnostic Groups.
|
||||||
class DiagGroup<string Name, list<DiagGroup> subgroups = []> {
|
class DiagGroup<string Name, list<DiagGroup> subgroups = []> {
|
||||||
string GroupName = Name;
|
string GroupName = Name;
|
||||||
list<DiagGroup> SubGroups = subgroups;
|
list<DiagGroup> SubGroups = subgroups;
|
||||||
string CategoryName = "";
|
string CategoryName = "";
|
||||||
|
code Documentation = [{}];
|
||||||
}
|
}
|
||||||
class InGroup<DiagGroup G> { DiagGroup Group = G; }
|
class InGroup<DiagGroup G> { DiagGroup Group = G; }
|
||||||
|
//class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; }
|
||||||
|
|
||||||
|
include "DiagnosticDocs.inc"
|
||||||
|
|
||||||
// All diagnostics emitted by the compiler are an indirect subclass of this.
|
// All diagnostics emitted by the compiler are an indirect subclass of this.
|
||||||
class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
|
class Diagnostic<string text, DiagClass DC, Severity defaultmapping> {
|
||||||
string Text = text;
|
/// Component is specified by the file with a big let directive.
|
||||||
DiagClass Class = DC;
|
string Component = ?;
|
||||||
DiagMapping DefaultMapping = defaultmapping;
|
string Text = text;
|
||||||
DiagGroup Group;
|
DiagClass Class = DC;
|
||||||
string CategoryName = "";
|
SFINAEResponse SFINAE = SFINAE_Suppress;
|
||||||
|
bit AccessControl = 0;
|
||||||
|
bit WarningNoWerror = 0;
|
||||||
|
bit ShowInSystemHeader = 0;
|
||||||
|
Severity DefaultSeverity = defaultmapping;
|
||||||
|
DiagGroup Group;
|
||||||
|
string CategoryName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
|
class SFINAEFailure {
|
||||||
class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>;
|
SFINAEResponse SFINAE = SFINAE_SubstitutionFailure;
|
||||||
class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>;
|
}
|
||||||
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>;
|
class NoSFINAE {
|
||||||
class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>;
|
SFINAEResponse SFINAE = SFINAE_Report;
|
||||||
|
}
|
||||||
|
class AccessControl {
|
||||||
|
SFINAEResponse SFINAE = SFINAE_AccessControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShowInSystemHeader {
|
||||||
|
bit ShowInSystemHeader = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SuppressInSystemHeader {
|
||||||
|
bit ShowInSystemHeader = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: ExtWarn and Extension should also be SFINAEFailure by default.
|
||||||
|
class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure {
|
||||||
|
bit ShowInSystemHeader = 1;
|
||||||
|
}
|
||||||
|
// Warnings default to on (but can be default-off'd with DefaultIgnore).
|
||||||
|
// This is used for warnings about questionable code; warnings about
|
||||||
|
// accepted language extensions should use Extension or ExtWarn below instead.
|
||||||
|
class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>;
|
||||||
|
// Remarks can be turned on with -R flags and provide commentary, e.g. on
|
||||||
|
// optimizer decisions.
|
||||||
|
class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>;
|
||||||
|
// Extensions are warnings about accepted language extensions.
|
||||||
|
// Extension warnings are default-off but enabled by -pedantic.
|
||||||
|
class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>;
|
||||||
|
// ExtWarns are warnings about accepted language extensions.
|
||||||
|
// ExtWarn warnings are default-on.
|
||||||
|
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>;
|
||||||
|
// Notes can provide supplementary information on errors, warnings, and remarks.
|
||||||
|
class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>;
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultIgnore { Severity DefaultSeverity = SEV_Ignored; }
|
||||||
|
class DefaultWarn { Severity DefaultSeverity = SEV_Warning; }
|
||||||
|
class DefaultError { Severity DefaultSeverity = SEV_Error; }
|
||||||
|
class DefaultFatal { Severity DefaultSeverity = SEV_Fatal; }
|
||||||
|
class DefaultWarnNoWerror {
|
||||||
|
bit WarningNoWerror = 1;
|
||||||
|
}
|
||||||
|
class DefaultRemark { Severity DefaultSeverity = SEV_Remark; }
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
|
||||||
|
def GlobalDocumentation {
|
||||||
|
code Intro =[{..
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
NOTE: This file is automatically generated by running clang-tblgen
|
||||||
|
-gen-diag-docs. Do not edit this file by hand!!
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
.. Add custom CSS to output. FIXME: This should be put into <head> rather
|
||||||
|
than the start of <body>.
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table.docutils {
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
table.docutils td {
|
||||||
|
border: none;
|
||||||
|
padding: 0 0 0 0.2em;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 1px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
table.docutils tr + tr {
|
||||||
|
border-top: 0.2em solid #aaa;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #c00;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #80a;
|
||||||
|
}
|
||||||
|
.remark {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #00c;
|
||||||
|
}
|
||||||
|
.diagtext {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
.. FIXME: rST doesn't support formatting this, so we format all <td> elements
|
||||||
|
as monospace font face instead.
|
||||||
|
.. |nbsp| unicode:: 0xA0
|
||||||
|
:trim:
|
||||||
|
|
||||||
|
.. Roles generated by clang-tblgen.
|
||||||
|
.. role:: error
|
||||||
|
.. role:: warning
|
||||||
|
.. role:: remark
|
||||||
|
.. role:: diagtext
|
||||||
|
.. role:: placeholder(emphasis)
|
||||||
|
|
||||||
|
=========================
|
||||||
|
Diagnostic flags in Clang
|
||||||
|
=========================
|
||||||
|
.. contents::
|
||||||
|
:local:
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This page lists the diagnostic flags currently supported by Clang.
|
||||||
|
|
||||||
|
Diagnostic flags
|
||||||
|
================
|
||||||
|
}];
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
// RUN: clang-tblgen -gen-diag-docs -I%S %s -o - 2>&1 | \
|
||||||
|
// RUN: FileCheck --strict-whitespace %s
|
||||||
|
include "DiagnosticBase.inc"
|
||||||
|
|
||||||
|
def MyGroup : DiagGroup<"MyGroupName">;
|
||||||
|
|
||||||
|
def MyKinds : TextSubstitution<"%select{food|forests}0">;
|
||||||
|
def MyGoodBad : TextSubstitution<"%select{good|bad}0">;
|
||||||
|
def MySubNested : TextSubstitution<"%sub{MyGoodBad}1 %sub{MyKinds}2 are %sub{MyGoodBad}1 according to %0">;
|
||||||
|
|
||||||
|
// CHECK: -WMyGroupName
|
||||||
|
// CHECK: **Diagnostic text:**
|
||||||
|
|
||||||
|
let Group = MyGroup in {
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`this is my diff text`|
|
||||||
|
// CHECK-NEXT: +-----------------------------------------------------------+
|
||||||
|
def CheckDiff : Warning<"%diff{$ is not $|this is my diff text}0,1">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is my modifier test` |nbsp| :placeholder:`B`|
|
||||||
|
// CHECK-NEXT: +----------------------------------------------------------------------------------------------------------+
|
||||||
|
def CheckModifier : Warning<"%0 is my modifier test %1">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`This is the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`test I've written`|
|
||||||
|
// CHECK-NEXT: +---------------------------------------------------------------------------------------------------------------+
|
||||||
|
def CheckOrdinal : Warning<"This is the %ordinal0 test I've written">;
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`I wrote` |nbsp| |+----------------+| |nbsp| :diagtext:`tests`|
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`no` || |
|
||||||
|
// CHECK-NEXT: | |+----------------+| |
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`one` || |
|
||||||
|
// CHECK-NEXT: | |+----------------+| |
|
||||||
|
// CHECK-NEXT: | ||:placeholder:`A`|| |
|
||||||
|
// CHECK-NEXT: | |+----------------+| |
|
||||||
|
// CHECK-NEXT: +------------------------------------------------------+------------------+-------------------------+
|
||||||
|
def CheckPlural : Warning<"I wrote %plural{0:no|1:one|:%0}0 tests">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`bad type` |nbsp| :placeholder:`A`|
|
||||||
|
// CHECK-NEXT: +-----------------------------------------------------------------------+
|
||||||
|
def CheckQ : Warning<"bad type %q0">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`My test`|+-------------+| |nbsp| :diagtext:`are the best!`|
|
||||||
|
// CHECK-NEXT: | || || |
|
||||||
|
// CHECK-NEXT: | |+-------------+| |
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`s`|| |
|
||||||
|
// CHECK-NEXT: | |+-------------+| |
|
||||||
|
// CHECK-NEXT: +----------------------------------------------+---------------+---------------------------------+
|
||||||
|
def CheckS : Warning<"My test%s0 are the best!">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`this is my select test:` |nbsp| |+---------------+|
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`one`||
|
||||||
|
// CHECK-NEXT: | |+---------------+|
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`two`||
|
||||||
|
// CHECK-NEXT: | |+---------------+|
|
||||||
|
// CHECK-NEXT: +----------------------------------------------------------------------+-----------------+
|
||||||
|
def CheckSelect : Warning<"this is my select test: %select{one|two}0 and it is %select{good|bad}1">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: +-------------------------------------------------------+------------------+--------+---------------------+-------------------------------+------------------+--------------------------------------------------------+
|
||||||
|
// CHECK-NEXT: |:warning:`warning:` |nbsp| :diagtext:`They say` |nbsp| |+----------------+| |nbsp| |+-------------------+| |nbsp| :diagtext:`are` |nbsp| |+----------------+| |nbsp| :diagtext:`according to` |nbsp| :placeholder:`D`|
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`good`|| ||:diagtext:`food` || ||:diagtext:`good`|| |
|
||||||
|
// CHECK-NEXT: | |+----------------+| |+-------------------+| |+----------------+| |
|
||||||
|
// CHECK-NEXT: | ||:diagtext:`bad` || ||:diagtext:`forests`|| ||:diagtext:`bad` || |
|
||||||
|
// CHECK-NEXT: | |+----------------+| |+-------------------+| |+----------------+| |
|
||||||
|
// CHECK-NEXT: +-------------------------------------------------------+------------------+--------+---------------------+-------------------------------+------------------+--------------------------------------------------------+
|
||||||
|
def CheckSubstitution : Warning<"They say %sub{MySubNested}3,1,0">;
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK: |:warning:`warning:` |nbsp| :diagtext:`this is my warning text`|
|
||||||
|
// CHECK-NEXT: +--------------------------------------------------------------+
|
||||||
|
def CheckText : Warning<"this is my warning text">;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// RUN: clang-tblgen -gen-clang-diags-defs -I%S %s -o - 2>&1 | \
|
||||||
|
// RUN: FileCheck --strict-whitespace %s
|
||||||
|
include "DiagnosticBase.inc"
|
||||||
|
|
||||||
|
def yes_no : TextSubstitution<"%select{yes|no}0">;
|
||||||
|
def says_yes : TextSubstitution<"%1 says %sub{yes_no}0">;
|
||||||
|
|
||||||
|
|
||||||
|
def sub_test_rewrite : TextSubstitution<
|
||||||
|
"SELECT! %select{one|two}3. "
|
||||||
|
"DIFF! %diff{$ is $|or not}0,1. "
|
||||||
|
"PLURAL! %plural{0:zero items|[1,2]:one or two item|:multiple items}2. "
|
||||||
|
"ORDINAL! %ordinal1. "
|
||||||
|
"S! item%s2. "
|
||||||
|
"Q! %q4. "
|
||||||
|
"PLACEHOLDER! %5."
|
||||||
|
"OBJCCLASS! %objcclass0. "
|
||||||
|
"OBJCINSTANCE! %objcinstance1. ">;
|
||||||
|
|
||||||
|
// CHECK: DIAG(test_rewrite,
|
||||||
|
// CHECK-SAME: SELECT! %select{one|two}2.
|
||||||
|
// CHECK-SAME: DIFF! %diff{$ is $|or not}5,4.
|
||||||
|
// CHECK-SAME: PLURAL! %plural{0:zero items|[1,2]:one or two item|:multiple items}3.
|
||||||
|
// CHECK-SAME: ORDINAL! %ordinal4.
|
||||||
|
// CHECK-SAME: S! item%s3.
|
||||||
|
// CHECK-SAME: Q! %q1.
|
||||||
|
// CHECK-SAME: PLACEHOLDER! %0.OBJCCLASS!
|
||||||
|
// CHECK-SAME: %objcclass5. OBJCINSTANCE!
|
||||||
|
// CHECK-SAME: %objcinstance4. DONE!",
|
||||||
|
def test_rewrite: Error<"%sub{sub_test_rewrite}5,4,3,2,1,0 DONE!">;
|
||||||
|
|
||||||
|
def test_sub_basic : Error<"%sub{yes_no}0">;
|
||||||
|
// CHECK: test_sub_basic
|
||||||
|
// CHECK-SAME: "%select{yes|no}0",
|
||||||
|
|
||||||
|
def test_sub_nested : Error<"%sub{says_yes}2,4">;
|
||||||
|
// CHECK: test_sub_nested
|
||||||
|
// CHECK-SAME: "%4 says %select{yes|no}2",
|
|
@ -57,7 +57,8 @@ config.substitutions.append(('%PATH%', config.environment['PATH']))
|
||||||
tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir]
|
tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir]
|
||||||
|
|
||||||
tools = [
|
tools = [
|
||||||
'c-index-test', 'clang-check', 'clang-diff', 'clang-format', 'opt',
|
'c-index-test', 'clang-check', 'clang-diff', 'clang-format', 'clang-tblgen',
|
||||||
|
'opt',
|
||||||
ToolSubst('%clang_func_map', command=FindTool(
|
ToolSubst('%clang_func_map', command=FindTool(
|
||||||
'clang-func-mapping'), unresolved='ignore'),
|
'clang-func-mapping'), unresolved='ignore'),
|
||||||
]
|
]
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue