https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/181105
>From e9ba82815b5e9cdcb3e20573e8359cf92c839ed3 Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Thu, 12 Feb 2026 16:28:30 +0800 Subject: [PATCH] [Clang] Keep the deduced TSI in sync with its DeducedTemplateSpecializationType The deduced TSI of CTAD was not tracked in VarDecl, creating an inconsistency with the deduced type. This inconsistency confused the template instantiator. We now propagate the TSI up from DeduceTemplateSpecializationFromInitializer, allowing its caller to update the VarDecl accordingly. Ideally deduceVarTypeFromInitializer should propagate that too, but that involves refactoring of DeduceAutoType and it isn't currently necessary to DeducedTemplateSpecializationType. Also this happened to resolve a FIXME from module's test. --- .../include-cleaner/unittests/WalkASTTest.cpp | 6 ++--- clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/SemaDecl.cpp | 11 +++++++-- clang/lib/Sema/SemaExprCXX.cpp | 8 ++++--- clang/lib/Sema/SemaInit.cpp | 24 +++++++++---------- clang/lib/Sema/SemaTemplate.cpp | 3 ++- clang/test/Modules/odr_hash.cpp | 3 ++- clang/test/SemaCXX/ctad.cpp | 14 +++++++++++ 9 files changed, 48 insertions(+), 24 deletions(-) diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 3487f24f2af8f..68a3a20045f6c 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -171,11 +171,9 @@ TEST(WalkAST, ClassTemplates) { template struct Foo<int>;)cpp", "^Foo<int> x;"), ElementsAre(Decl::CXXRecord)); - // FIXME: This is broken due to - // https://github.com/llvm/llvm-project/issues/42259. EXPECT_THAT(testWalk(R"cpp( - template<typename T> struct $explicit^Foo { Foo(T); }; - template<> struct Foo<int> { Foo(int); };)cpp", + template<typename T> struct Foo { Foo(T); }; + template<> struct $explicit^Foo<int> { Foo(int); };)cpp", "^Foo x(3);"), ElementsAre(Decl::ClassTemplate)); } diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7dc6881ed43e6..de55659645b5c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -235,6 +235,7 @@ Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402) - Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639) +- Fixed a type deduction bug where CTAD didn't apply to designated initializers. (#GH178879) - Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741) Bug Fixes to AST Handling diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0ba3daab764b7..efcdc994ecbc7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9077,7 +9077,7 @@ class Sema final : public SemaBase { bool TopLevelOfInitList = false, bool AllowExplicit = false); - QualType DeduceTemplateSpecializationFromInitializer( + TypeSourceInfo *DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Init); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3b2c93b9fe7b5..5d75e05bdce66 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13279,8 +13279,15 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, VDecl->getLocation(), DirectInit, Init); // FIXME: Initialization should not be taking a mutable list of inits. SmallVector<Expr *, 8> InitsCopy(DeduceInits); - return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, - InitsCopy); + TypeSourceInfo *DeducedTSI = DeduceTemplateSpecializationFromInitializer( + TSI, Entity, Kind, InitsCopy); + if (DeducedTSI) { + // DeduceVariableDeclarationType will update the type from DeducedTSI. + // FIXME: Propagate TSI up, but it's difficult for DeduceAutoType. + VDecl->setTypeSourceInfo(DeducedTSI); + return DeducedTSI->getType(); + } + return QualType(); } if (DirectInit) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 91967a7a9ff97..cb231ab4ecf86 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1549,8 +1549,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, DeducedType *Deduced = Ty->getContainedDeducedType(); if (Deduced && !Deduced->isDeduced() && isa<DeducedTemplateSpecializationType>(Deduced)) { - Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity, - Kind, Exprs); + TypeSourceInfo *TSI = + DeduceTemplateSpecializationFromInitializer(TInfo, Entity, Kind, Exprs); + Ty = TSI ? TSI->getType() : QualType(); if (Ty.isNull()) return ExprError(); Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); @@ -2208,8 +2209,9 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); - AllocType = DeduceTemplateSpecializationFromInitializer( + TypeSourceInfo *TSI = DeduceTemplateSpecializationFromInitializer( AllocTypeInfo, Entity, Kind, Exprs); + AllocType = TSI ? TSI->getType() : QualType(); if (AllocType.isNull()) return ExprError(); } else if (Deduced && !Deduced->isDeduced()) { diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index ff278bc7471bd..fa5fbfccf98f1 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10062,7 +10062,7 @@ static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD, return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization)); } -QualType Sema::DeduceTemplateSpecializationFromInitializer( +TypeSourceInfo *Sema::DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TSInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Inits) { auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>( @@ -10071,7 +10071,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( auto TemplateName = DeducedTST->getTemplateName(); if (TemplateName.isDependent()) - return SubstAutoTypeSourceInfoDependent(TSInfo)->getType(); + return SubstAutoTypeSourceInfoDependent(TSInfo); // We can only perform deduction for class templates or alias templates. auto *Template = @@ -10108,7 +10108,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( << (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName; if (auto *TD = TemplateName.getAsTemplateDecl()) NoteTemplateLocation(*TD); - return QualType(); + return nullptr; } // Can't deduce from dependent arguments. @@ -10116,7 +10116,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 0; - return SubstAutoTypeSourceInfoDependent(TSInfo)->getType(); + return SubstAutoTypeSourceInfoDependent(TSInfo); } // FIXME: Perform "exact type" matching first, per CWG discussion? @@ -10381,7 +10381,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( PDiag(diag::err_deduced_class_template_ctor_ambiguous) << TemplateName), *this, OCD_AmbiguousCandidates, Inits); - return QualType(); + return nullptr; case OR_No_Viable_Function: { CXXRecordDecl *Primary = @@ -10395,7 +10395,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( : diag::err_deduced_class_template_incomplete) << TemplateName << !Guides.empty()), *this, OCD_AllCandidates, Inits); - return QualType(); + return nullptr; } case OR_Deleted: { @@ -10405,7 +10405,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted) << TemplateName; NoteDeletedFunction(Best->Function); - return QualType(); + return nullptr; } case OR_Success: @@ -10420,7 +10420,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(Best->Function->getLocation(), diag::note_explicit_ctor_deduction_guide_here) << IsDeductionGuide; - return QualType(); + return nullptr; } // Make sure we didn't select an unusable deduction guide, and mark it @@ -10433,9 +10433,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // C++ [dcl.type.class.deduct]p1: // The placeholder is replaced by the return type of the function selected // by overload resolution for class template deduction. - QualType DeducedType = - SubstAutoTypeSourceInfo(TSInfo, Best->Function->getReturnType()) - ->getType(); + TypeSourceInfo *DeducedTSI = + SubstAutoTypeSourceInfo(TSInfo, Best->Function->getReturnType()); + QualType DeducedType = DeducedTSI ? DeducedTSI->getType() : QualType(); Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType; @@ -10449,5 +10449,5 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(Template->getLocation(), diag::note_suppress_ctad_maybe_unsupported); } - return DeducedType; + return DeducedTSI; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3497ff7856eed..4475e6d490218 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -7145,8 +7145,9 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, InitializationKind Kind = InitializationKind::CreateForInit( DeductionArg->getBeginLoc(), /*DirectInit*/false, DeductionArg); Expr *Inits[1] = {DeductionArg}; - ParamType = + auto *DeducedTSI = DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits); + ParamType = DeducedTSI ? DeducedTSI->getType() : QualType(); if (ParamType.isNull()) return ExprError(); } else { diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index f22f3c71f44d2..daf229a2176fe 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -3883,7 +3883,8 @@ void valid() { } #else auto function1 = invalid1; -// FIXME: We should reject the merge of `invalid1` due to the inconsistent definition. +// [email protected]:* {{'Types::DeducedTemplateSpecialization::invalid1' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} +// [email protected]:* {{but in 'FirstModule' found a different body}} auto function2 = invalid2; // [email protected]:* {{'Types::DeducedTemplateSpecialization::invalid2' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}} // [email protected]:* {{but in 'FirstModule' found a different body}} diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp index 7de7f50337e8c..91173f7331255 100644 --- a/clang/test/SemaCXX/ctad.cpp +++ b/clang/test/SemaCXX/ctad.cpp @@ -197,3 +197,17 @@ namespace GH131342 { template <class T> using AA = A<T, val<T>>; AA a{0}; } // namespace GH131342 + +namespace GH178879 { + +template <typename T> struct A { + T i, j; +}; + +template <typename T> void foo() { + A a = {.i = 1, .j = 3}; +} + +template void foo<int>(); + +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
