Skip to content

Commit 001cc34

Browse files
authored
[clang] Add scoped enum support to StreamingDiagnostic (#138089)
This patch adds templated `operator<<` for diagnostics that pass scoped enums, saving people from `llvm::to_underlying()` clutter on the side of emitting the diagnostic. This eliminates 80 out of 220 usages of `llvm::to_underlying()` in Clang. I also backported `std::is_scoped_enum_v` from C++23.
1 parent a6459de commit 001cc34

25 files changed

+105
-125
lines changed

clang/include/clang/Basic/Diagnostic.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,22 @@ operator<<(const StreamingDiagnostic &DB, T *DC) {
14291429
return DB;
14301430
}
14311431

1432+
// Convert scope enums to their underlying type, so that we don't have
1433+
// clutter the emitting code with `llvm::to_underlying()`.
1434+
// We also need to disable implicit conversion for the first argument,
1435+
// because classes that derive from StreamingDiagnostic define their own
1436+
// templated operator<< that accept a wide variety of types, leading
1437+
// to ambiguity.
1438+
template <typename T, typename U>
1439+
inline std::enable_if_t<
1440+
std::is_same_v<std::remove_const_t<T>, StreamingDiagnostic> &&
1441+
llvm::is_scoped_enum_v<std::remove_reference_t<U>>,
1442+
const StreamingDiagnostic &>
1443+
operator<<(const T &DB, U &&SE) {
1444+
DB << llvm::to_underlying(SE);
1445+
return DB;
1446+
}
1447+
14321448
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
14331449
SourceLocation L) {
14341450
DB.AddSourceRange(CharSourceRange::getTokenRange(L));

clang/include/clang/Sema/Sema.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -220,11 +220,6 @@ enum class AssignmentAction {
220220
Casting,
221221
Passing_CFAudited
222222
};
223-
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
224-
const AssignmentAction &AA) {
225-
DB << llvm::to_underlying(AA);
226-
return DB;
227-
}
228223

229224
namespace threadSafety {
230225
class BeforeSet;
@@ -15471,12 +15466,6 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
1547115466
llvm::StringRef StackSlotLabel,
1547215467
AlignPackInfo Value);
1547315468

15474-
inline const StreamingDiagnostic &
15475-
operator<<(const StreamingDiagnostic &DB, Sema::StringEvaluationContext Ctx) {
15476-
DB << llvm::to_underlying(Ctx);
15477-
return DB;
15478-
}
15479-
1548015469
} // end namespace clang
1548115470

1548215471
#endif

clang/lib/AST/ODRDiagsEmitter.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,8 @@ bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod(
461461
}
462462
if (FirstMethod->getImplementationControl() !=
463463
SecondMethod->getImplementationControl()) {
464-
DiagError(ControlLevel)
465-
<< llvm::to_underlying(FirstMethod->getImplementationControl());
466-
DiagNote(ControlLevel) << llvm::to_underlying(
467-
SecondMethod->getImplementationControl());
464+
DiagError(ControlLevel) << FirstMethod->getImplementationControl();
465+
DiagNote(ControlLevel) << SecondMethod->getImplementationControl();
468466
return true;
469467
}
470468
if (FirstMethod->isThisDeclarationADesignatedInitializer() !=

clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2578,7 +2578,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
25782578
if (TemplateInfo.Kind != ParsedTemplateKind::NonTemplate &&
25792579
D.isFirstDeclarator()) {
25802580
Diag(CommaLoc, diag::err_multiple_template_declarators)
2581-
<< llvm::to_underlying(TemplateInfo.Kind);
2581+
<< TemplateInfo.Kind;
25822582
}
25832583

25842584
// Parse the next declarator.

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3472,7 +3472,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
34723472
if (TemplateInfo.Kind != ParsedTemplateKind::NonTemplate &&
34733473
DeclaratorInfo.isFirstDeclarator()) {
34743474
Diag(CommaLoc, diag::err_multiple_template_declarators)
3475-
<< llvm::to_underlying(TemplateInfo.Kind);
3475+
<< TemplateInfo.Kind;
34763476
}
34773477

34783478
// Parse the next declarator.

clang/lib/Parse/ParsePragma.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2341,7 +2341,8 @@ void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
23412341
SourceLocation PragmaLocation = Tok.getLocation();
23422342
PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text']
23432343
if (Tok.isNot(tok::equal)) {
2344-
PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << llvm::to_underlying(SecKind);
2344+
PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal)
2345+
<< SecKind;
23452346
return;
23462347
}
23472348

clang/lib/Parse/Parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
226226

227227
if (Kind != ExtraSemiKind::AfterMemberFunctionDefinition || HadMultipleSemis)
228228
Diag(StartLoc, diag::ext_extra_semi)
229-
<< llvm::to_underlying(Kind)
229+
<< Kind
230230
<< DeclSpec::getSpecifierName(
231231
TST, Actions.getASTContext().getPrintingPolicy())
232232
<< FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));

clang/lib/Sema/SemaAccess.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,24 +1670,21 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
16701670
case InitializedEntity::EK_Base:
16711671
PD = PDiag(diag::err_access_base_ctor);
16721672
PD << Entity.isInheritedVirtualBase()
1673-
<< Entity.getBaseSpecifier()->getType()
1674-
<< llvm::to_underlying(getSpecialMember(Constructor));
1673+
<< Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
16751674
break;
16761675

16771676
case InitializedEntity::EK_Member:
16781677
case InitializedEntity::EK_ParenAggInitMember: {
16791678
const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
16801679
PD = PDiag(diag::err_access_field_ctor);
1681-
PD << Field->getType()
1682-
<< llvm::to_underlying(getSpecialMember(Constructor));
1680+
PD << Field->getType() << getSpecialMember(Constructor);
16831681
break;
16841682
}
16851683

16861684
case InitializedEntity::EK_LambdaCapture: {
16871685
StringRef VarName = Entity.getCapturedVarName();
16881686
PD = PDiag(diag::err_access_lambda_capture);
1689-
PD << VarName << Entity.getType()
1690-
<< llvm::to_underlying(getSpecialMember(Constructor));
1687+
PD << VarName << Entity.getType() << getSpecialMember(Constructor);
16911688
break;
16921689
}
16931690

clang/lib/Sema/SemaCUDA.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,7 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
450450
if (Diagnose) {
451451
Diag(ClassDecl->getLocation(),
452452
diag::note_implicit_member_target_infer_collision)
453-
<< (unsigned)CSM << llvm::to_underlying(*InferredTarget)
454-
<< llvm::to_underlying(BaseMethodTarget);
453+
<< (unsigned)CSM << *InferredTarget << BaseMethodTarget;
455454
}
456455
MemberDecl->addAttr(
457456
CUDAInvalidTargetAttr::CreateImplicit(getASTContext()));
@@ -496,8 +495,7 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
496495
if (Diagnose) {
497496
Diag(ClassDecl->getLocation(),
498497
diag::note_implicit_member_target_infer_collision)
499-
<< (unsigned)CSM << llvm::to_underlying(*InferredTarget)
500-
<< llvm::to_underlying(FieldMethodTarget);
498+
<< (unsigned)CSM << *InferredTarget << FieldMethodTarget;
501499
}
502500
MemberDecl->addAttr(
503501
CUDAInvalidTargetAttr::CreateImplicit(getASTContext()));
@@ -713,7 +711,7 @@ void SemaCUDA::checkAllowedInitializer(VarDecl *VD) {
713711
if (InitFnTarget != CUDAFunctionTarget::Host &&
714712
InitFnTarget != CUDAFunctionTarget::HostDevice) {
715713
Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer)
716-
<< llvm::to_underlying(InitFnTarget) << InitFn;
714+
<< InitFnTarget << InitFn;
717715
Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn;
718716
VD->setInvalidDecl();
719717
}
@@ -952,8 +950,8 @@ bool SemaCUDA::CheckCall(SourceLocation Loc, FunctionDecl *Callee) {
952950

953951
SemaDiagnosticBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller,
954952
SemaRef)
955-
<< llvm::to_underlying(IdentifyTarget(Callee)) << /*function*/ 0 << Callee
956-
<< llvm::to_underlying(IdentifyTarget(Caller));
953+
<< IdentifyTarget(Callee) << /*function*/ 0 << Callee
954+
<< IdentifyTarget(Caller);
957955
if (!Callee->getBuiltinID())
958956
SemaDiagnosticBuilder(DiagKind, Callee->getLocation(),
959957
diag::note_previous_decl, Caller, SemaRef)
@@ -1049,8 +1047,7 @@ void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD,
10491047
(NewTarget == CUDAFunctionTarget::Global) ||
10501048
(OldTarget == CUDAFunctionTarget::Global)) {
10511049
Diag(NewFD->getLocation(), diag::err_cuda_ovl_target)
1052-
<< llvm::to_underlying(NewTarget) << NewFD->getDeclName()
1053-
<< llvm::to_underlying(OldTarget) << OldFD;
1050+
<< NewTarget << NewFD->getDeclName() << OldTarget << OldFD;
10541051
Diag(OldFD->getLocation(), diag::note_previous_declaration);
10551052
NewFD->setInvalidDecl();
10561053
break;
@@ -1060,7 +1057,7 @@ void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD,
10601057
(NewTarget == CUDAFunctionTarget::Device &&
10611058
OldTarget == CUDAFunctionTarget::Host)) {
10621059
Diag(NewFD->getLocation(), diag::warn_offload_incompatible_redeclare)
1063-
<< llvm::to_underlying(NewTarget) << llvm::to_underlying(OldTarget);
1060+
<< NewTarget << OldTarget;
10641061
Diag(OldFD->getLocation(), diag::note_previous_declaration);
10651062
}
10661063
}

clang/lib/Sema/SemaChecking.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8339,8 +8339,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
83398339
} else {
83408340
EmitFormatDiagnostic(
83418341
S.PDiag(diag::warn_non_pod_vararg_with_format_string)
8342-
<< S.getLangOpts().CPlusPlus11 << ExprTy
8343-
<< llvm::to_underlying(CallType)
8342+
<< S.getLangOpts().CPlusPlus11 << ExprTy << CallType
83448343
<< AT.getRepresentativeTypeName(S.Context) << CSR
83458344
<< E->getSourceRange(),
83468345
E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
@@ -8354,16 +8353,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
83548353
else if (ExprTy->isObjCObjectType())
83558354
EmitFormatDiagnostic(
83568355
S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format)
8357-
<< S.getLangOpts().CPlusPlus11 << ExprTy
8358-
<< llvm::to_underlying(CallType)
8356+
<< S.getLangOpts().CPlusPlus11 << ExprTy << CallType
83598357
<< AT.getRepresentativeTypeName(S.Context) << CSR
83608358
<< E->getSourceRange(),
83618359
E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
83628360
else
83638361
// FIXME: If this is an initializer list, suggest removing the braces
83648362
// or inserting a cast to the target type.
83658363
S.Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg_format)
8366-
<< isa<InitListExpr>(E) << ExprTy << llvm::to_underlying(CallType)
8364+
<< isa<InitListExpr>(E) << ExprTy << CallType
83678365
<< AT.getRepresentativeTypeName(S.Context) << E->getSourceRange();
83688366
break;
83698367
}

clang/lib/Sema/SemaDecl.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4034,13 +4034,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
40344034
} else {
40354035
Diag(NewMethod->getLocation(),
40364036
diag::err_definition_of_implicitly_declared_member)
4037-
<< New << llvm::to_underlying(getSpecialMember(OldMethod));
4037+
<< New << getSpecialMember(OldMethod);
40384038
return true;
40394039
}
40404040
} else if (OldMethod->getFirstDecl()->isExplicitlyDefaulted() && !isFriend) {
40414041
Diag(NewMethod->getLocation(),
40424042
diag::err_definition_of_explicitly_defaulted_member)
4043-
<< llvm::to_underlying(getSpecialMember(OldMethod));
4043+
<< getSpecialMember(OldMethod);
40444044
return true;
40454045
}
40464046
}
@@ -5249,7 +5249,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
52495249
if (DS.isModulePrivateSpecified() &&
52505250
Tag && Tag->getDeclContext()->isFunctionOrMethod())
52515251
Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class)
5252-
<< llvm::to_underlying(Tag->getTagKind())
5252+
<< Tag->getTagKind()
52535253
<< FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
52545254

52555255
ActOnDocumentableDecl(TagD);
@@ -7722,15 +7722,14 @@ NamedDecl *Sema::ActOnVariableDeclarator(
77227722
// data members.
77237723
Diag(D.getIdentifierLoc(),
77247724
diag::err_static_data_member_not_allowed_in_local_class)
7725-
<< Name << RD->getDeclName()
7726-
<< llvm::to_underlying(RD->getTagKind());
7725+
<< Name << RD->getDeclName() << RD->getTagKind();
77277726
} else if (AnonStruct) {
77287727
// C++ [class.static.data]p4: Unnamed classes and classes contained
77297728
// directly or indirectly within unnamed classes shall not contain
77307729
// static data members.
77317730
Diag(D.getIdentifierLoc(),
77327731
diag::err_static_data_member_not_allowed_in_anon_struct)
7733-
<< Name << llvm::to_underlying(AnonStruct->getTagKind());
7732+
<< Name << AnonStruct->getTagKind();
77347733
Invalid = true;
77357734
} else if (RD->isUnion()) {
77367735
// C++98 [class.union]p1: If a union contains a static data member,
@@ -17661,7 +17660,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
1766117660

1766217661
// A tag 'foo::bar' must already exist.
1766317662
Diag(NameLoc, diag::err_not_tag_in_scope)
17664-
<< llvm::to_underlying(Kind) << Name << DC << SS.getRange();
17663+
<< Kind << Name << DC << SS.getRange();
1766517664
Name = nullptr;
1766617665
Invalid = true;
1766717666
goto CreateNewDecl;
@@ -18119,7 +18118,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
1811918118
!Previous.isForRedeclaration()) {
1812018119
NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind);
1812118120
Diag(NameLoc, diag::err_tag_reference_non_tag)
18122-
<< PrevDecl << NTK << llvm::to_underlying(Kind);
18121+
<< PrevDecl << NTK << Kind;
1812318122
Diag(PrevDecl->getLocation(), diag::note_declared_at);
1812418123
Invalid = true;
1812518124

@@ -19018,8 +19017,7 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
1901819017
getLangOpts().CPlusPlus11
1901919018
? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member
1902019019
: diag::err_illegal_union_or_anon_struct_member)
19021-
<< FD->getParent()->isUnion() << FD->getDeclName()
19022-
<< llvm::to_underlying(member);
19020+
<< FD->getParent()->isUnion() << FD->getDeclName() << member;
1902319021
DiagnoseNontrivial(RDecl, member);
1902419022
return !getLangOpts().CPlusPlus11;
1902519023
}
@@ -19359,8 +19357,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1935919357
unsigned DiagID = 0;
1936019358
if (!Record->isUnion() && !IsLastField) {
1936119359
Diag(FD->getLocation(), diag::err_flexible_array_not_at_end)
19362-
<< FD->getDeclName() << FD->getType()
19363-
<< llvm::to_underlying(Record->getTagKind());
19360+
<< FD->getDeclName() << FD->getType() << Record->getTagKind();
1936419361
Diag((*(i + 1))->getLocation(), diag::note_next_field_declaration);
1936519362
FD->setInvalidDecl();
1936619363
EnclosingDecl->setInvalidDecl();
@@ -19376,18 +19373,18 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1937619373

1937719374
if (DiagID)
1937819375
Diag(FD->getLocation(), DiagID)
19379-
<< FD->getDeclName() << llvm::to_underlying(Record->getTagKind());
19376+
<< FD->getDeclName() << Record->getTagKind();
1938019377
// While the layout of types that contain virtual bases is not specified
1938119378
// by the C++ standard, both the Itanium and Microsoft C++ ABIs place
1938219379
// virtual bases after the derived members. This would make a flexible
1938319380
// array member declared at the end of an object not adjacent to the end
1938419381
// of the type.
1938519382
if (CXXRecord && CXXRecord->getNumVBases() != 0)
1938619383
Diag(FD->getLocation(), diag::err_flexible_array_virtual_base)
19387-
<< FD->getDeclName() << llvm::to_underlying(Record->getTagKind());
19384+
<< FD->getDeclName() << Record->getTagKind();
1938819385
if (!getLangOpts().C99)
1938919386
Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
19390-
<< FD->getDeclName() << llvm::to_underlying(Record->getTagKind());
19387+
<< FD->getDeclName() << Record->getTagKind();
1939119388

1939219389
// If the element type has a non-trivial destructor, we would not
1939319390
// implicitly destroy the elements, so disallow it for now.

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5058,7 +5058,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
50585058
}
50595059
if (S.getLangOpts().CUDA && VD->hasLocalStorage() &&
50605060
S.CUDA().DiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
5061-
<< llvm::to_underlying(S.CUDA().CurrentTarget()))
5061+
<< S.CUDA().CurrentTarget())
50625062
return;
50635063
D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
50645064
}

0 commit comments

Comments
 (0)