llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Vlad Serebrennikov (Endilll) <details> <summary>Changes</summary> 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. --- Patch is 40.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138089.diff 25 Files Affected: - (modified) clang/include/clang/Basic/Diagnostic.h (+16) - (modified) clang/include/clang/Sema/Sema.h (-11) - (modified) clang/lib/AST/ODRDiagsEmitter.cpp (+2-4) - (modified) clang/lib/Parse/ParseDecl.cpp (+1-1) - (modified) clang/lib/Parse/ParseDeclCXX.cpp (+1-1) - (modified) clang/lib/Parse/ParsePragma.cpp (+2-1) - (modified) clang/lib/Parse/Parser.cpp (+1-1) - (modified) clang/lib/Sema/SemaAccess.cpp (+3-6) - (modified) clang/lib/Sema/SemaCUDA.cpp (+7-10) - (modified) clang/lib/Sema/SemaChecking.cpp (+3-5) - (modified) clang/lib/Sema/SemaDecl.cpp (+12-15) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+1-1) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+28-34) - (modified) clang/lib/Sema/SemaDeclObjC.cpp (+1-1) - (modified) clang/lib/Sema/SemaExpr.cpp (+7-11) - (modified) clang/lib/Sema/SemaExprCXX.cpp (+1-1) - (modified) clang/lib/Sema/SemaInit.cpp (+1-2) - (modified) clang/lib/Sema/SemaOverload.cpp (+2-3) - (modified) clang/lib/Sema/SemaStmt.cpp (+1-1) - (modified) clang/lib/Sema/SemaTemplate.cpp (+3-5) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+2-3) - (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+2-2) - (modified) clang/lib/Sema/SemaType.cpp (+1-1) - (modified) clang/lib/Sema/TreeTransform.h (+3-5) - (modified) llvm/include/llvm/ADT/STLForwardCompat.h (+4) ``````````diff diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 19524856a9bb3..92ab61b95a7c6 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -1429,6 +1429,22 @@ operator<<(const StreamingDiagnostic &DB, T *DC) { return DB; } +// Convert scope enums to their underlying type, so that we don't have +// clutter the emitting code with `llvm::to_underlying()`. +// We also need to disable implicit conversion for the first argument, +// because classes that derive from StreamingDiagnostic define their own +// templated operator<< that accept a wide variety of types, leading +// to ambiguity. +template <typename T, typename U> +inline std::enable_if_t< + std::is_same_v<std::remove_const_t<T>, StreamingDiagnostic> && + llvm::is_scoped_enum_v<std::remove_reference_t<U>>, + const StreamingDiagnostic &> +operator<<(const T &DB, U &&SE) { + DB << llvm::to_underlying(SE); + return DB; +} + inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, SourceLocation L) { DB.AddSourceRange(CharSourceRange::getTokenRange(L)); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 28313f45b1228..003583f84cf97 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -220,11 +220,6 @@ enum class AssignmentAction { Casting, Passing_CFAudited }; -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, - const AssignmentAction &AA) { - DB << llvm::to_underlying(AA); - return DB; -} namespace threadSafety { class BeforeSet; @@ -15471,12 +15466,6 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation, llvm::StringRef StackSlotLabel, AlignPackInfo Value); -inline const StreamingDiagnostic & -operator<<(const StreamingDiagnostic &DB, Sema::StringEvaluationContext Ctx) { - DB << llvm::to_underlying(Ctx); - return DB; -} - } // end namespace clang #endif diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp index 37f0f68c92355..74f3881ed3c96 100644 --- a/clang/lib/AST/ODRDiagsEmitter.cpp +++ b/clang/lib/AST/ODRDiagsEmitter.cpp @@ -461,10 +461,8 @@ bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod( } if (FirstMethod->getImplementationControl() != SecondMethod->getImplementationControl()) { - DiagError(ControlLevel) - << llvm::to_underlying(FirstMethod->getImplementationControl()); - DiagNote(ControlLevel) << llvm::to_underlying( - SecondMethod->getImplementationControl()); + DiagError(ControlLevel) << FirstMethod->getImplementationControl(); + DiagNote(ControlLevel) << SecondMethod->getImplementationControl(); return true; } if (FirstMethod->isThisDeclarationADesignatedInitializer() != diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 9dd9d9c637592..cd6464678c4b5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2578,7 +2578,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, if (TemplateInfo.Kind != ParsedTemplateKind::NonTemplate && D.isFirstDeclarator()) { Diag(CommaLoc, diag::err_multiple_template_declarators) - << llvm::to_underlying(TemplateInfo.Kind); + << TemplateInfo.Kind; } // Parse the next declarator. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 8dfc0fa53dd88..7e0a8af07a3be 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3472,7 +3472,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration( if (TemplateInfo.Kind != ParsedTemplateKind::NonTemplate && DeclaratorInfo.isFirstDeclarator()) { Diag(CommaLoc, diag::err_multiple_template_declarators) - << llvm::to_underlying(TemplateInfo.Kind); + << TemplateInfo.Kind; } // Parse the next declarator. diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 026a35639abdf..9f9e4bb92af8c 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -2341,7 +2341,8 @@ void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, SourceLocation PragmaLocation = Tok.getLocation(); PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text'] if (Tok.isNot(tok::equal)) { - PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << llvm::to_underlying(SecKind); + PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) + << SecKind; return; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 120d44238ea35..ec87317897200 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -226,7 +226,7 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) { if (Kind != ExtraSemiKind::AfterMemberFunctionDefinition || HadMultipleSemis) Diag(StartLoc, diag::ext_extra_semi) - << llvm::to_underlying(Kind) + << Kind << DeclSpec::getSpecifierName( TST, Actions.getASTContext().getPrintingPolicy()) << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index b77cbdb234f1f..890df09157aa0 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -1670,24 +1670,21 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, case InitializedEntity::EK_Base: PD = PDiag(diag::err_access_base_ctor); PD << Entity.isInheritedVirtualBase() - << Entity.getBaseSpecifier()->getType() - << llvm::to_underlying(getSpecialMember(Constructor)); + << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); break; case InitializedEntity::EK_Member: case InitializedEntity::EK_ParenAggInitMember: { const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); PD = PDiag(diag::err_access_field_ctor); - PD << Field->getType() - << llvm::to_underlying(getSpecialMember(Constructor)); + PD << Field->getType() << getSpecialMember(Constructor); break; } case InitializedEntity::EK_LambdaCapture: { StringRef VarName = Entity.getCapturedVarName(); PD = PDiag(diag::err_access_lambda_capture); - PD << VarName << Entity.getType() - << llvm::to_underlying(getSpecialMember(Constructor)); + PD << VarName << Entity.getType() << getSpecialMember(Constructor); break; } diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 0a8c24f8be537..45595068ea938 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -450,8 +450,7 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, if (Diagnose) { Diag(ClassDecl->getLocation(), diag::note_implicit_member_target_infer_collision) - << (unsigned)CSM << llvm::to_underlying(*InferredTarget) - << llvm::to_underlying(BaseMethodTarget); + << (unsigned)CSM << *InferredTarget << BaseMethodTarget; } MemberDecl->addAttr( CUDAInvalidTargetAttr::CreateImplicit(getASTContext())); @@ -496,8 +495,7 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, if (Diagnose) { Diag(ClassDecl->getLocation(), diag::note_implicit_member_target_infer_collision) - << (unsigned)CSM << llvm::to_underlying(*InferredTarget) - << llvm::to_underlying(FieldMethodTarget); + << (unsigned)CSM << *InferredTarget << FieldMethodTarget; } MemberDecl->addAttr( CUDAInvalidTargetAttr::CreateImplicit(getASTContext())); @@ -713,7 +711,7 @@ void SemaCUDA::checkAllowedInitializer(VarDecl *VD) { if (InitFnTarget != CUDAFunctionTarget::Host && InitFnTarget != CUDAFunctionTarget::HostDevice) { Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) - << llvm::to_underlying(InitFnTarget) << InitFn; + << InitFnTarget << InitFn; Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; VD->setInvalidDecl(); } @@ -952,8 +950,8 @@ bool SemaCUDA::CheckCall(SourceLocation Loc, FunctionDecl *Callee) { SemaDiagnosticBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, SemaRef) - << llvm::to_underlying(IdentifyTarget(Callee)) << /*function*/ 0 << Callee - << llvm::to_underlying(IdentifyTarget(Caller)); + << IdentifyTarget(Callee) << /*function*/ 0 << Callee + << IdentifyTarget(Caller); if (!Callee->getBuiltinID()) SemaDiagnosticBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl, Caller, SemaRef) @@ -1049,8 +1047,7 @@ void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD, (NewTarget == CUDAFunctionTarget::Global) || (OldTarget == CUDAFunctionTarget::Global)) { Diag(NewFD->getLocation(), diag::err_cuda_ovl_target) - << llvm::to_underlying(NewTarget) << NewFD->getDeclName() - << llvm::to_underlying(OldTarget) << OldFD; + << NewTarget << NewFD->getDeclName() << OldTarget << OldFD; Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); break; @@ -1060,7 +1057,7 @@ void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD, (NewTarget == CUDAFunctionTarget::Device && OldTarget == CUDAFunctionTarget::Host)) { Diag(NewFD->getLocation(), diag::warn_offload_incompatible_redeclare) - << llvm::to_underlying(NewTarget) << llvm::to_underlying(OldTarget); + << NewTarget << OldTarget; Diag(OldFD->getLocation(), diag::note_previous_declaration); } } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2d648898cdea1..92ec2fec519b1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8339,8 +8339,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, } else { EmitFormatDiagnostic( S.PDiag(diag::warn_non_pod_vararg_with_format_string) - << S.getLangOpts().CPlusPlus11 << ExprTy - << llvm::to_underlying(CallType) + << S.getLangOpts().CPlusPlus11 << ExprTy << CallType << AT.getRepresentativeTypeName(S.Context) << CSR << E->getSourceRange(), E->getBeginLoc(), /*IsStringLocation*/ false, CSR); @@ -8354,8 +8353,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, else if (ExprTy->isObjCObjectType()) EmitFormatDiagnostic( S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format) - << S.getLangOpts().CPlusPlus11 << ExprTy - << llvm::to_underlying(CallType) + << S.getLangOpts().CPlusPlus11 << ExprTy << CallType << AT.getRepresentativeTypeName(S.Context) << CSR << E->getSourceRange(), E->getBeginLoc(), /*IsStringLocation*/ false, CSR); @@ -8363,7 +8361,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // FIXME: If this is an initializer list, suggest removing the braces // or inserting a cast to the target type. S.Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg_format) - << isa<InitListExpr>(E) << ExprTy << llvm::to_underlying(CallType) + << isa<InitListExpr>(E) << ExprTy << CallType << AT.getRepresentativeTypeName(S.Context) << E->getSourceRange(); break; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 56396cddf57b8..092cfcf48fc1d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4034,13 +4034,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) - << New << llvm::to_underlying(getSpecialMember(OldMethod)); + << New << getSpecialMember(OldMethod); return true; } } else if (OldMethod->getFirstDecl()->isExplicitlyDefaulted() && !isFriend) { Diag(NewMethod->getLocation(), diag::err_definition_of_explicitly_defaulted_member) - << llvm::to_underlying(getSpecialMember(OldMethod)); + << getSpecialMember(OldMethod); return true; } } @@ -5246,7 +5246,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (DS.isModulePrivateSpecified() && Tag && Tag->getDeclContext()->isFunctionOrMethod()) Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) - << llvm::to_underlying(Tag->getTagKind()) + << Tag->getTagKind() << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); ActOnDocumentableDecl(TagD); @@ -7719,15 +7719,14 @@ NamedDecl *Sema::ActOnVariableDeclarator( // data members. Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_local_class) - << Name << RD->getDeclName() - << llvm::to_underlying(RD->getTagKind()); + << Name << RD->getDeclName() << RD->getTagKind(); } else if (AnonStruct) { // C++ [class.static.data]p4: Unnamed classes and classes contained // directly or indirectly within unnamed classes shall not contain // static data members. Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_anon_struct) - << Name << llvm::to_underlying(AnonStruct->getTagKind()); + << Name << AnonStruct->getTagKind(); Invalid = true; } else if (RD->isUnion()) { // C++98 [class.union]p1: If a union contains a static data member, @@ -17658,7 +17657,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) - << llvm::to_underlying(Kind) << Name << DC << SS.getRange(); + << Kind << Name << DC << SS.getRange(); Name = nullptr; Invalid = true; goto CreateNewDecl; @@ -18116,7 +18115,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, !Previous.isForRedeclaration()) { NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); Diag(NameLoc, diag::err_tag_reference_non_tag) - << PrevDecl << NTK << llvm::to_underlying(Kind); + << PrevDecl << NTK << Kind; Diag(PrevDecl->getLocation(), diag::note_declared_at); Invalid = true; @@ -19015,8 +19014,7 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member : diag::err_illegal_union_or_anon_struct_member) - << FD->getParent()->isUnion() << FD->getDeclName() - << llvm::to_underlying(member); + << FD->getParent()->isUnion() << FD->getDeclName() << member; DiagnoseNontrivial(RDecl, member); return !getLangOpts().CPlusPlus11; } @@ -19356,8 +19354,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, unsigned DiagID = 0; if (!Record->isUnion() && !IsLastField) { Diag(FD->getLocation(), diag::err_flexible_array_not_at_end) - << FD->getDeclName() << FD->getType() - << llvm::to_underlying(Record->getTagKind()); + << FD->getDeclName() << FD->getType() << Record->getTagKind(); Diag((*(i + 1))->getLocation(), diag::note_next_field_declaration); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); @@ -19373,7 +19370,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (DiagID) Diag(FD->getLocation(), DiagID) - << FD->getDeclName() << llvm::to_underlying(Record->getTagKind()); + << FD->getDeclName() << Record->getTagKind(); // While the layout of types that contain virtual bases is not specified // by the C++ standard, both the Itanium and Microsoft C++ ABIs place // virtual bases after the derived members. This would make a flexible @@ -19381,10 +19378,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // of the type. if (CXXRecord && CXXRecord->getNumVBases() != 0) Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) - << FD->getDeclName() << llvm::to_underlying(Record->getTagKind()); + << FD->getDeclName() << Record->getTagKind(); if (!getLangOpts().C99) Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) - << FD->getDeclName() << llvm::to_underlying(Record->getTagKind()); + << FD->getDeclName() << Record->getTagKind(); // If the element type has a non-trivial destructor, we would not // implicitly destroy the elements, so disallow it for now. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ab66ae860f86b..9d6a1c77f5aaf 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5058,7 +5058,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (S.getLangOpts().CUDA && VD->hasLocalStorage() && S.CUDA().DiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) - << llvm::to_underlying(S.CUDA().CurrentTarget())) + << S.CUDA().CurrentTarget()) return; D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL)); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 645a0887c0f19..a7e68682d5320 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -647,7 +647,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, ParmVarDecl *NewParam = New->getParamDecl(New->getMinRequiredArguments()); assert(NewParam->hasDefaultArg()); Diag(NewParam->getLocation(), diag::err_default_arg_makes_ctor_special) - << NewParam->getDefaultArgRange() << llvm::to_underlying(NewSM); + << NewParam->getDefaultArgRange() << NewSM; Diag(Old->getLocation(), diag::note_previous_declaration); } } @@ -6978,7 +6978,7 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { (F->getType().isConstQualified() && F->getType()->isScalarType())) { if (!Complained) { Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst) - << llvm::to_underlying(Record->getTagKind()) << Record; + << Record->getTagKind() << Record; Complained = true; } @@ -7774,14 +7774,14 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // default argument is classified as a default constructor, and assignment // operations and destructors can't have default arguments. Diag(MD->getLocation(), diag::err_defaulted_special_member_params) - << llvm::to_underlying(CSM) << MD->getSourceRange(); + << CSM << MD->getSourceRange(); HadError = true; } else if (MD->isVariadic()) { if (DeleteOnTypeMismatch) ShouldDeleteForTypeMismatch = true; else { Diag(MD->getLocation(), diag::err_defaulted_special_member_variadic) - << llvm::to_underlying(CSM) << MD->getSourceRange(); + << CSM << MD->getSourceRange(); HadError = true; } } @@ -7868,7 +7868,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, else { Diag... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/138089 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits