llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

<details>
<summary>Changes</summary>

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.

Fixes https://github.com/llvm/llvm-project/issues/178879

---
Full diff: https://github.com/llvm/llvm-project/pull/181105.diff


8 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/include/clang/Sema/Sema.h (+1-1) 
- (modified) clang/lib/Sema/SemaDecl.cpp (+9-2) 
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+5-3) 
- (modified) clang/lib/Sema/SemaInit.cpp (+12-12) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+2-1) 
- (modified) clang/test/Modules/odr_hash.cpp (+2-1) 
- (modified) clang/test/SemaCXX/ctad.cpp (+14) 


``````````diff
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>();
+
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/181105
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to