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
|
||||
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:
|
||||
|
||||
Producing the Diagnostic
|
||||
|
|
|
@ -39,6 +39,15 @@ 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> {
|
||||
|
|
|
@ -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 "
|
||||
"%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_ivar_decl : Note<"instance variable 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_member_synthesized_at : Note<
|
||||
"in implicit %select{default constructor|copy constructor|move constructor|"
|
||||
"copy assignment operator|move assignment operator|destructor}0 for %1 "
|
||||
"in implicit %sub{select_special_member_kind}0 for %1 "
|
||||
"first required here">;
|
||||
def err_missing_default_ctor : Error<
|
||||
"%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<
|
||||
"%select{anonymous struct|union}0 member %1 has a non-trivial "
|
||||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
||||
"operator|move assignment operator|destructor}2">;
|
||||
"%sub{select_special_member_kind}2">;
|
||||
def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
|
||||
"%select{anonymous struct|union}0 member %1 with a non-trivial "
|
||||
"%select{constructor|copy constructor|move constructor|copy assignment "
|
||||
"operator|move assignment operator|destructor}2 is incompatible with C++98">,
|
||||
"%sub{select_special_member_kind}2 is incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
||||
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">;
|
||||
def note_nontrivial_user_provided : Note<
|
||||
"because %select{base class of |field of |}0type %1 has a user-provided "
|
||||
"%select{default constructor|copy constructor|move constructor|"
|
||||
"copy assignment operator|move assignment operator|destructor}2">;
|
||||
"%sub{select_special_member_kind}2">;
|
||||
def note_nontrivial_in_class_init : Note<
|
||||
"because field %0 has an initializer">;
|
||||
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
|
||||
def note_in_declaration_of_implicit_special_member : Note<
|
||||
"while declaring the implicit "
|
||||
"%select{default constructor|copy constructor|move constructor|"
|
||||
"copy assignment operator|move assignment operator|destructor}1"
|
||||
"while declaring the implicit %sub{select_special_member_kind}1"
|
||||
" for %0">;
|
||||
|
||||
// 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}2 function">;
|
||||
def note_implicit_member_target_infer_collision : Note<
|
||||
"implicit %select{"
|
||||
"default constructor|"
|
||||
"copy constructor|"
|
||||
"move constructor|"
|
||||
"copy assignment operator|"
|
||||
"move assignment operator|"
|
||||
"destructor}0 inferred target collision: call to both "
|
||||
"implicit %sub{select_special_member_kind}0 inferred target collision: call to both "
|
||||
"%select{__device__|__global__|__host__|__host__ __device__}1 and "
|
||||
"%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">;
|
||||
def err_ovl_deleted_special_oper : Error<
|
||||
"object of type %0 cannot be %select{constructed|copied|moved|assigned|"
|
||||
"assigned|destroyed}1 because its %select{default constructor|"
|
||||
"copy constructor|move constructor|copy assignment operator|"
|
||||
"move assignment operator|destructor}1 is implicitly deleted">;
|
||||
"assigned|destroyed}1 because its %sub{select_special_member_kind}1 is implicitly deleted">;
|
||||
def err_ovl_no_viable_subscript :
|
||||
Error<"no viable overloaded operator[] for type %0">;
|
||||
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 "
|
||||
"have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">;
|
||||
def err_defaulted_special_member_volatile_param : Error<
|
||||
"the parameter for an explicitly-defaulted %select{<<ERROR>>|"
|
||||
"copy constructor|move constructor|copy assignment operator|"
|
||||
"move assignment operator|<<ERROR>>}0 may not be volatile">;
|
||||
"the parameter for an explicitly-defaulted %sub{select_special_member_kind}0 "
|
||||
"may not be volatile">;
|
||||
def err_defaulted_special_member_move_const_param : Error<
|
||||
"the parameter for an explicitly-defaulted move "
|
||||
"%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 "
|
||||
"lvalue reference type">;
|
||||
def err_incorrect_defaulted_exception_spec : Error<
|
||||
"exception specification of explicitly defaulted %select{default constructor|"
|
||||
"copy constructor|move constructor|copy assignment operator|move assignment "
|
||||
"operator|destructor}0 does not match the "
|
||||
"calculated one">;
|
||||
"exception specification of explicitly defaulted "
|
||||
"%sub{select_special_member_kind}0 does not match the calculated one">;
|
||||
def err_incorrect_defaulted_constexpr : Error<
|
||||
"defaulted definition of %select{default constructor|copy constructor|"
|
||||
"move constructor|copy assignment operator|move assignment operator}0 "
|
||||
"defaulted definition of %sub{select_special_member_kind}0 "
|
||||
"is not constexpr">;
|
||||
def err_out_of_line_default_deletes : Error<
|
||||
"defaulting this %select{default constructor|copy constructor|move "
|
||||
"constructor|copy assignment operator|move assignment operator|destructor}0 "
|
||||
"defaulting this %sub{select_special_member_kind}0 "
|
||||
"would delete it after its first declaration">;
|
||||
def warn_vbase_moved_multiple_times : Warning<
|
||||
"defaulted move assignment operator of %0 will move assign virtual base "
|
||||
|
|
|
@ -16,7 +16,7 @@ struct E {
|
|||
struct {
|
||||
S x;
|
||||
#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
|
||||
};
|
||||
static struct {
|
||||
|
|
|
@ -241,13 +241,13 @@ namespace UnionOrAnonStructMembers {
|
|||
~NonTrivDtor(); // expected-note 2{{user-provided destructor}}
|
||||
};
|
||||
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}}
|
||||
NonTrivDtor ntd; // expected-warning {{union member 'ntd' with a non-trivial destructor is incompatible with C++98}}
|
||||
};
|
||||
struct Wrap {
|
||||
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}}
|
||||
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 {
|
||||
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.
|
||||
class DiagMapping;
|
||||
def MAP_IGNORE : DiagMapping;
|
||||
def MAP_WARNING : DiagMapping;
|
||||
def MAP_ERROR : DiagMapping;
|
||||
def MAP_FATAL : DiagMapping;
|
||||
//===--- DiagnosticBase.inc - A test file mimicking Diagnostic.td ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// 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.
|
||||
class DiagClass;
|
||||
def CLASS_NOTE : DiagClass;
|
||||
def CLASS_REMARK : DiagClass;
|
||||
def CLASS_WARNING : DiagClass;
|
||||
def CLASS_EXTENSION : 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 = []> {
|
||||
string GroupName = Name;
|
||||
list<DiagGroup> SubGroups = subgroups;
|
||||
string CategoryName = "";
|
||||
code Documentation = [{}];
|
||||
}
|
||||
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.
|
||||
class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
|
||||
class Diagnostic<string text, DiagClass DC, Severity defaultmapping> {
|
||||
/// Component is specified by the file with a big let directive.
|
||||
string Component = ?;
|
||||
string Text = text;
|
||||
DiagClass Class = DC;
|
||||
DiagMapping DefaultMapping = defaultmapping;
|
||||
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 Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>;
|
||||
class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>;
|
||||
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>;
|
||||
class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>;
|
||||
class SFINAEFailure {
|
||||
SFINAEResponse SFINAE = SFINAE_SubstitutionFailure;
|
||||
}
|
||||
class NoSFINAE {
|
||||
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]
|
||||
|
||||
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(
|
||||
'clang-func-mapping'), unresolved='ignore'),
|
||||
]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue