Skip to content

Commit bf17016

Browse files
Add 'enum_select' diagnostic selection to clang. (#122505)
This causes us to generate an enum to go along with the select diagnostic, which allows for clearer diagnostic error emit lines. The syntax for this is: %enum_select<EnumerationName>{%OptionalEnumeratorName{Text}|{Text2}}0 Where the curley brackets around the select-text are only required if an Enumerator name is provided. The TableGen here emits this as a normal 'select' to the frontend, which permits us to reuse all of the existing 'select' infrastructure. Documentation is the same as well. --------- Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
1 parent d15d410 commit bf17016

21 files changed

+464
-17
lines changed

clang/docs/InternalsManual.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,21 @@ Description:
276276
diagnostic instead of having to do things textually. The selected string
277277
does undergo formatting.
278278

279+
**"enum_select format**
280+
281+
Example:
282+
``unknown frobbling of a %enum_select<FrobbleKind>{%VarDecl{variable declaration}|%FuncDecl{function declaration}}0 when blarging``
283+
Class:
284+
Integers
285+
Description:
286+
This format specifier is used exactly like a ``select`` specifier, except it
287+
additionally generates a namespace, enumeration, and enumerator list based on
288+
the format string given. In the above case, a namespace is generated named
289+
``FrobbleKind`` that has an unscoped enumeration with the enumerators
290+
``VarDecl`` and ``FuncDecl`` which correspond to the values 0 and 1. This
291+
permits a clearer use of the ``Diag`` in source code, as the above could be
292+
called as: ``Diag(Loc, diag::frobble) << diag::FrobbleKind::VarDecl``.
293+
279294
**"plural" format**
280295

281296
Example:

clang/include/clang/Basic/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ macro(clang_diag_gen component)
33
-gen-clang-diags-defs -clang-component=${component}
44
SOURCE Diagnostic.td
55
TARGET ClangDiagnostic${component})
6+
7+
clang_tablegen(Diagnostic${component}Enums.inc
8+
-gen-clang-diags-enums -clang-component=${component}
9+
SOURCE Diagnostic.td
10+
TARGET ClangDiagnostic${component}Enums)
611
endmacro(clang_diag_gen)
712

813
clang_diag_gen(Analysis)

clang/include/clang/Basic/DiagnosticAST.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_AST_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticASTEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticAnalysis.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_ANALYSIS_DIAGNOSTICS
2424
};
25+
#define DIAG_ENUM(ENUM_NAME) \
26+
namespace ENUM_NAME { \
27+
enum {
28+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
29+
#define DIAG_ENUM_END() \
30+
} \
31+
; \
32+
}
33+
#include "clang/Basic/DiagnosticAnalysisEnums.inc"
34+
#undef DIAG_ENUM_END
35+
#undef DIAG_ENUM_ITEM
36+
#undef DIAG_ENUM
2537
} // end namespace diag
2638
} // end namespace clang
2739

clang/include/clang/Basic/DiagnosticComment.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_COMMENT_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticCommentEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticCrossTU.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_CROSSTU_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticCrossTUEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticDriver.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_DRIVER_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticDriverEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticFrontend.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_FRONTEND_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticFrontendEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticInstallAPI.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ enum {
2121
#undef DIAG
2222
NUM_BUILTIN_INSTALLAPI_DIAGNOSTICS
2323
};
24+
25+
#define DIAG_ENUM(ENUM_NAME) \
26+
namespace ENUM_NAME { \
27+
enum {
28+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
29+
#define DIAG_ENUM_END() \
30+
} \
31+
; \
32+
}
33+
#include "clang/Basic/DiagnosticInstallAPIEnums.inc"
34+
#undef DIAG_ENUM_END
35+
#undef DIAG_ENUM_ITEM
36+
#undef DIAG_ENUM
2437
} // namespace diag
2538
} // namespace clang
2639
#endif // LLVM_CLANG_BASIC_DIAGNOSTICINSTALLAPI_H

clang/include/clang/Basic/DiagnosticLex.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_LEX_DIAGNOSTICS
2424
};
25+
#define DIAG_ENUM(ENUM_NAME) \
26+
namespace ENUM_NAME { \
27+
enum {
28+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
29+
#define DIAG_ENUM_END() \
30+
} \
31+
; \
32+
}
33+
#include "clang/Basic/DiagnosticLexEnums.inc"
34+
#undef DIAG_ENUM_END
35+
#undef DIAG_ENUM_ITEM
36+
#undef DIAG_ENUM
2537
} // end namespace diag
2638
} // end namespace clang
2739

clang/include/clang/Basic/DiagnosticParse.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_PARSE_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticParseEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticRefactoring.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_REFACTORING_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticRefactoringEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticSema.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_SEMA_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticSemaEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -617,9 +617,11 @@ def err_ambiguous_inherited_constructor : Error<
617617
"constructor of %0 inherited from multiple base class subobjects">;
618618
def note_ambiguous_inherited_constructor_using : Note<
619619
"inherited from base class %0 here">;
620-
def note_using_decl_class_member_workaround : Note<
621-
"use %select{an alias declaration|a typedef declaration|a reference|"
622-
"a const variable|a constexpr variable}0 instead">;
620+
def note_using_decl_class_member_workaround
621+
: Note<"use %enum_select<MemClassWorkaround>{%AliasDecl{an alias "
622+
"declaration}|%TypedefDecl{a typedef declaration}|%ReferenceDecl{a "
623+
"reference}|%ConstVar{a const variable}|%ConstexprVar{a constexpr "
624+
"variable}}0 instead">;
623625
def err_using_decl_can_not_refer_to_namespace : Error<
624626
"using declaration cannot refer to a namespace">;
625627
def note_namespace_using_decl : Note<

clang/include/clang/Basic/DiagnosticSerialization.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ enum {
2222
#undef DIAG
2323
NUM_BUILTIN_SERIALIZATION_DIAGNOSTICS
2424
};
25+
26+
#define DIAG_ENUM(ENUM_NAME) \
27+
namespace ENUM_NAME { \
28+
enum {
29+
#define DIAG_ENUM_ITEM(IDX, NAME) NAME = IDX,
30+
#define DIAG_ENUM_END() \
31+
} \
32+
; \
33+
}
34+
#include "clang/Basic/DiagnosticSerializationEnums.inc"
35+
#undef DIAG_ENUM_END
36+
#undef DIAG_ENUM_ITEM
37+
#undef DIAG_ENUM
2538
} // end namespace diag
2639
} // end namespace clang
2740

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13217,18 +13217,18 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
1321713217
if (getLangOpts().CPlusPlus11) {
1321813218
// Convert 'using X::Y;' to 'using Y = X::Y;'.
1321913219
Diag(SS.getBeginLoc(), diag::note_using_decl_class_member_workaround)
13220-
<< 0 // alias declaration
13221-
<< FixItHint::CreateInsertion(SS.getBeginLoc(),
13222-
NameInfo.getName().getAsString() +
13223-
" = ");
13220+
<< diag::MemClassWorkaround::AliasDecl
13221+
<< FixItHint::CreateInsertion(SS.getBeginLoc(),
13222+
NameInfo.getName().getAsString() +
13223+
" = ");
1322413224
} else {
1322513225
// Convert 'using X::Y;' to 'typedef X::Y Y;'.
1322613226
SourceLocation InsertLoc = getLocForEndOfToken(NameInfo.getEndLoc());
1322713227
Diag(InsertLoc, diag::note_using_decl_class_member_workaround)
13228-
<< 1 // typedef declaration
13229-
<< FixItHint::CreateReplacement(UsingLoc, "typedef")
13230-
<< FixItHint::CreateInsertion(
13231-
InsertLoc, " " + NameInfo.getName().getAsString());
13228+
<< diag::MemClassWorkaround::TypedefDecl
13229+
<< FixItHint::CreateReplacement(UsingLoc, "typedef")
13230+
<< FixItHint::CreateInsertion(
13231+
InsertLoc, " " + NameInfo.getName().getAsString());
1323213232
}
1323313233
} else if (R->getAsSingle<VarDecl>()) {
1323413234
// Don't provide a fixit outside C++11 mode; we don't want to suggest
@@ -13241,8 +13241,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
1324113241
}
1324213242

1324313243
Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
13244-
<< 2 // reference declaration
13245-
<< FixIt;
13244+
<< diag::MemClassWorkaround::ReferenceDecl << FixIt;
1324613245
} else if (R->getAsSingle<EnumConstantDecl>()) {
1324713246
// Don't provide a fixit outside C++11 mode; we don't want to suggest
1324813247
// repeating the type of the enumeration here, and we can't do so if
@@ -13256,8 +13255,10 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
1325613255
}
1325713256

1325813257
Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
13259-
<< (getLangOpts().CPlusPlus11 ? 4 : 3) // const[expr] variable
13260-
<< FixIt;
13258+
<< (getLangOpts().CPlusPlus11
13259+
? diag::MemClassWorkaround::ConstexprVar
13260+
: diag::MemClassWorkaround::ConstVar)
13261+
<< FixIt;
1326113262
}
1326213263
}
1326313264

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: not clang-tblgen --gen-clang-diags-enums -DERROR1 -I%S %s 2>&1 | FileCheck %s --check-prefixes=CHECK,C1
2+
// RUN: not clang-tblgen --gen-clang-diags-enums -DERROR2 -I%S %s 2>&1 | FileCheck %s --check-prefixes=CHECK,C2
3+
// RUN: not clang-tblgen --gen-clang-diags-enums -DERROR3 -I%S %s 2>&1 | FileCheck %s --check-prefixes=CHECK,C3
4+
// RUN: not clang-tblgen --gen-clang-diags-enums -DERROR4 -I%S %s 2>&1 | FileCheck %s --check-prefixes=CHECK,C4
5+
include "DiagnosticBase.inc"
6+
7+
// No real reason to diagnose these, the namespace generated as the
8+
// 'enumeration' name will never conflict with the enumerator.
9+
def EnumerationEnumeratorDupe : Error<"%enum_select<Matchy>{%Matchy{haha}}0">;
10+
11+
// Enumerator values aren't required, though this does seem kind of silly/not
12+
// particularly useful?
13+
def NoEnumerators : Error<"%enum_select<Name>{foo|bar|baz}0">;
14+
15+
def DupeNames1 : Error<"%enum_select<DupeName>{}0">;
16+
def DupeNames2 : Error<"%enum_select<DupeName>{}0">;
17+
// CHECK: error: Duplicate enumeration name 'DupeName'
18+
// CHECK-NEXT: def DupeNames2
19+
// CHECK: note: Previous diagnostic is here
20+
// CHECK-NEXT: def DupeNames1
21+
22+
def DupeValue : Error<"%enum_select<DupeValue>{%DName{V1}|%DName{V2}}0">;
23+
// CHECK: error: Duplicate enumerator name 'DName'
24+
25+
#ifdef ERROR1
26+
def EnumValNotExpected : Error<"%enum_select{V1|%Val2{V2}}0">;
27+
// C1: expected '<' after enum_select
28+
#endif
29+
30+
#ifdef ERROR2
31+
def SelectWithArrow : Error<"%select<Something>{V1|%Val2{V2}}0">;
32+
// C2: modifier '<' syntax not valid with %select
33+
#endif
34+
35+
#ifdef ERROR3
36+
// Missing closing > after the name of the enumeration
37+
def MissingClosing : Error<"%enum_select<MissingClosingName{}0">;
38+
// C3: expected '>' while parsing %enum_select
39+
#endif
40+
41+
#ifdef ERROR4
42+
// Missing { after the name of an enumerator
43+
def MissingTextAfterEnumerator: Error<"%enum_select<Name>{%OtherName|foo}0">;
44+
// C4: expected '{' while parsing %enum_select
45+
#endif

0 commit comments

Comments
 (0)