https://github.com/mizvekov updated 
https://github.com/llvm/llvm-project/pull/159463

>From f0e35786d31bb99f31a625a67c89c211cbe6dac1 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <[email protected]>
Date: Wed, 17 Sep 2025 18:12:36 -0300
Subject: [PATCH] [clang] check constant template parameters in dependent
 contexts

This patch makes sure constant template parameters are checked even
in dependent contexts.

This can for example diagnose narrowings earlier, but this is permitted
as these templates would have no valid instantiations.
---
 clang/docs/ReleaseNotes.rst                   |  3 ++-
 clang/lib/Sema/SemaTemplate.cpp               |  5 ++--
 clang/test/SemaTemplate/temp_arg_template.cpp | 24 ++++++++++++-------
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 51e5973098c14..0eadc1c773597 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -241,7 +241,8 @@ Improvements to Clang's diagnostics
 - Fixed fix-it hint for fold expressions. Clang now correctly places the 
suggested right
   parenthesis when diagnosing malformed fold expressions. (#GH151787)
 - Added fix-it hint for when scoped enumerations require explicit conversions 
for binary operations. (#GH24265)
-
+- Constant template parameters are now type checked in template definitions,
+  including template template parameters.
 - Fixed an issue where emitted format-signedness diagnostics were not 
associated with an appropriate
   diagnostic id. Besides being incorrect from an API standpoint, this was user 
visible, e.g.:
   "format specifies type 'unsigned int' but the argument has type 'int' 
[-Wformat]"
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index d6b25c2d83613..faeba6ada0c6b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5482,9 +5482,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, 
TemplateArgumentLoc &ArgLoc,
     if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack())
       NTTPType = NTTP->getExpansionType(ArgumentPackIndex);
 
-    if (NTTPType->isInstantiationDependentType() &&
-        !isa<TemplateTemplateParmDecl>(Template) &&
-        !Template->getDeclContext()->isDependentContext()) {
+    if (NTTPType->isInstantiationDependentType()) {
       // Do substitution on the type of the non-type template parameter.
       InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP,
                                  CTAI.SugaredConverted,
@@ -5494,6 +5492,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, 
TemplateArgumentLoc &ArgLoc,
 
       MultiLevelTemplateArgumentList MLTAL(Template, CTAI.SugaredConverted,
                                            /*Final=*/true);
+      MLTAL.addOuterRetainedLevels(NTTP->getDepth());
       // If the parameter is a pack expansion, expand this slice of the pack.
       if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
         Sema::ArgPackSubstIndexRAII SubstIndex(*this, ArgumentPackIndex);
diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp 
b/clang/test/SemaTemplate/temp_arg_template.cpp
index aa53dba652050..431e19741ece9 100644
--- a/clang/test/SemaTemplate/temp_arg_template.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template.cpp
@@ -117,16 +117,8 @@ namespace CheckDependentNonTypeParamTypes {
       X<int, long, 3> x;
     }
     void h() {
-      // FIXME: If we accept A<B> at all, it's not obvious what should happen
-      // here. While parsing the template, we form
-      //   X<unsigned char, int, (unsigned char)1234>
-      // but in the final instantiation do we get
-      //   B<unsigned char, int, (int)1234>
-      // or
-      //   B<unsigned char, int, (int)(unsigned char)1234>
-      // ?
       X<unsigned char, int, 1234> x;
-      int check[x.value == 1234 ? 1 : -1];
+      // expected-error@-1 {{evaluates to 1234, which cannot be narrowed to 
type 'unsigned char'}}
     }
   };
 
@@ -143,6 +135,20 @@ namespace CheckDependentNonTypeParamTypes {
     ab.g();
     ab.h();
   }
+
+  template<class> struct C {
+    template<class T, T V> struct D {};
+    using T = D<char, 1234>;
+    // expected-error@-1 {{evaluates to 1234, which cannot be narrowed to type 
'char'}}
+  };
+
+  template<class T> struct E {
+    template <template <T V> class TT> struct F {
+      using X = TT<1234>;
+    };
+  };
+  // FIXME: This should be rejected, as there are no valid instantiations for 
E<char>::F
+  template struct E<char>;
 }
 
 namespace PR32185 {

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

Reply via email to