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 <mizve...@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits