[clang] [clang] create class-type injected NTTP with correct value kind (PR #101395)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 31 12:57:39 PDT 2024
https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/101395
A template parameter object is an lvalue, which was not being respected for injected parameters.
Fixes GH101394
>From 2d6d367408277b912c3db09cbbc7398c247c32c5 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Wed, 31 Jul 2024 16:54:02 -0300
Subject: [PATCH] [clang] create class-type injected NTTP with correct value
kind
A template parameter object is an lvalue, which was not being
respected for injected parameters.
Fixes GH101394
---
clang/docs/ReleaseNotes.rst | 4 +++-
clang/lib/AST/ASTContext.cpp | 16 ++++++++++++----
clang/lib/AST/ExprClassification.cpp | 9 +++++----
.../SemaTemplate/temp_arg_template_p0522.cpp | 18 ++++++++++++++++++
4 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3c2e0282d1c72..bb8f45887e01e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -130,7 +130,7 @@ Improvements to Clang's diagnostics
- Some template related diagnostics have been improved.
.. code-block:: c++
-
+
void foo() { template <typename> int i; } // error: templates can only be declared in namespace or class scope
struct S {
@@ -170,6 +170,8 @@ Bug Fixes to C++ Support
- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)
- Fix a crash when checking destructor reference with an invalid initializer. (#GH97230)
- Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators.
+- Fix a crash when matching template template parameters with templates which have
+ parameters of different class type. (#GH101394)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a465cdfcf3c89..5a90087882c85 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5588,11 +5588,19 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
// of a real template argument.
// FIXME: It would be more faithful to model this as something like an
// lvalue-to-rvalue conversion applied to a const-qualified lvalue.
- if (T->isRecordType())
+ ExprValueKind VK;
+ if (T->isRecordType()) {
+ // C++ [temp.param]p8: An id-expression naming a non-type
+ // template-parameter of class type T denotes a static storage duration
+ // object of type const T.
T.addConst();
- Expr *E = new (*this) DeclRefExpr(
- *this, NTTP, /*RefersToEnclosingVariableOrCapture*/ false, T,
- Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
+ VK = VK_LValue;
+ } else {
+ VK = Expr::getValueKindForType(NTTP->getType());
+ }
+ Expr *E = new (*this)
+ DeclRefExpr(*this, NTTP, /*RefersToEnclosingVariableOrCapture=*/false,
+ T, VK, NTTP->getLocation());
if (NTTP->isParameterPack())
E = new (*this)
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 6482cb6d39acc..d80e3a19a469b 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -471,12 +471,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
/// ClassifyDecl - Return the classification of an expression referencing the
/// given declaration.
static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
- // C++ [expr.prim.general]p6: The result is an lvalue if the entity is a
- // function, variable, or data member and a prvalue otherwise.
+ // C++ [expr.prim.id.unqual]p3: The result is an lvalue if the entity is a
+ // function, variable, or data member, or a template parameter object and a
+ // prvalue otherwise.
// In C, functions are not lvalues.
// In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an
- // lvalue unless it's a reference type (C++ [temp.param]p6), so we need to
- // special-case this.
+ // lvalue unless it's a reference type or a class type (C++ [temp.param]p8),
+ // so we need to special-case this.
if (const auto *M = dyn_cast<CXXMethodDecl>(D)) {
if (M->isImplicitObjectMemberFunction())
diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index 251b6fc7d2be1..6f6568b9ab776 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -126,3 +126,21 @@ namespace GH62529 {
template<class T4> B<A, T4> f();
auto t = f<int>();
} // namespace GH62529
+
+namespace GH101394 {
+ struct X {};
+ struct Y {
+ constexpr Y(const X &) {}
+ };
+
+ namespace t1 {
+ template<template<X> class> struct A {};
+ template<Y> struct B;
+ template struct A<B>;
+ } // namespace t1
+ namespace t2 {
+ template<template<Y> class> struct A {};
+ template<X> struct B;
+ template struct A<B>; // expected-error {{different template parameters}}
+ } // namespace t2
+} // namespace GH101394
More information about the cfe-commits
mailing list