[clang] [clang] Fix bad error recovery when classes are defined inside template (PR #142278)
Artyom Zabroda via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 4 04:17:00 PDT 2025
https://github.com/ArtyomZabroda updated https://github.com/llvm/llvm-project/pull/142278
>From 6fc280bb5583ee4f1713cb1447b8b86993b7abb7 Mon Sep 17 00:00:00 2001
From: Artyom Zabroda <artyomzabroda at gmail.com>
Date: Sat, 31 May 2025 18:44:21 +0300
Subject: [PATCH 1/2] [clang] Fix bad error recovery when classes are defined
inside template aliases
---
clang/lib/Sema/SemaConcept.cpp | 8 ++++++++
clang/lib/Sema/SemaDeclCXX.cpp | 9 ++++++++-
clang/test/SemaCXX/concept-crash-on-diagnostic.cpp | 13 +++++++++++++
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index c6a54dc141ded..1c654f46e23b3 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -220,6 +220,14 @@ static ExprResult EvaluateAtomicConstraint(
if (Inst.isInvalid())
return ExprError();
+ if (const TemplateTypeParmType *TTPT =
+ dyn_cast<TemplateTypeParmType>(AtomicExpr->getType().getDesugaredType(S.Context))) {
+ TemplateTypeParmDecl *TTPD = TTPT->getDecl();
+ if (TTPD->isInvalidDecl()) {
+ return ExprError();
+ }
+ }
+
llvm::FoldingSetNodeID ID;
if (Template &&
DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 55e078f3180a2..3efd18c0dcd96 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13717,8 +13717,15 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
const ParsedAttributesView &AttrList,
TypeResult Type, Decl *DeclFromDeclSpec) {
- if (Type.isInvalid())
+ if (Type.isInvalid()) {
+ for (TemplateParameterList *TPL : TemplateParamLists) {
+ for (NamedDecl *D : *TPL) {
+ D->setInvalidDecl(true);
+ }
+ }
return nullptr;
+ }
+
bool Invalid = false;
DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name);
diff --git a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
index 1efed72522fef..af254828b0fe7 100644
--- a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
+++ b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -60,3 +60,16 @@ concept atomicish = requires() {
};
atomicish<int> f(); // expected-error {{expected 'auto' or 'decltype(auto)' after concept name}}
} // namespace GH138820
+
+namespace GH91564 {
+template <class T> using A = struct B { // expected-error {{'GH91564::B' cannot be defined in a type alias template}}
+ template <class> void f() requires (T()); // expected-note {{candidate template ignored: failed template argument deduction}}
+};
+template void B::f<void>(); // expected-error {{explicit instantiation of 'f' does not refer to a function template, variable template, member function, member class, or static data member}}
+
+template <class T> using C = struct D { // expected-error {{'GH91564::D' cannot be defined in a type alias template}}
+ using E = T;
+};
+template <class> void g() requires (D::E()); // expected-note {{candidate template ignored: failed template argument deduction}}
+template void g<void>(); // expected-error {{explicit instantiation of 'g' does not refer to a function template, variable template, member function, member class, or static data member}}
+}
\ No newline at end of file
>From c52af95007c2efaac1d44f3ff36e6a8021d6b70f Mon Sep 17 00:00:00 2001
From: Artyom Zabroda <artyomzabroda at gmail.com>
Date: Wed, 4 Jun 2025 14:16:26 +0300
Subject: [PATCH 2/2] very inaccurate fix
---
clang/include/clang/Parse/Parser.h | 2 ++
clang/lib/Parse/ParseDeclCXX.cpp | 17 +++++++++++++++++
clang/lib/Sema/SemaConcept.cpp | 8 --------
clang/lib/Sema/SemaDecl.cpp | 4 ++--
clang/lib/Sema/SemaDeclCXX.cpp | 9 +--------
.../SemaCXX/concept-crash-on-diagnostic.cpp | 8 ++++----
6 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index c4bef4729fd36..90f17465bce7d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -8909,6 +8909,8 @@ class Parser : public CodeCompletionHandler {
bool OuterMightBeMessageSend = false);
///@}
+
+ TemplateParameterLists *TemplateParamsFromAlias = nullptr;
};
} // end namespace clang
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 2cf33a856c4f4..4069d257b0150 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -886,11 +886,17 @@ Decl *Parser::ParseAliasDeclarationAfterDeclarator(
<< FixItHint::CreateRemoval(SourceRange(D.EllipsisLoc));
Decl *DeclFromDeclSpec = nullptr;
+
+ this->TemplateParamsFromAlias = TemplateInfo.TemplateParams;
+
TypeResult TypeAlias =
ParseTypeName(nullptr,
TemplateInfo.Kind != ParsedTemplateKind::NonTemplate ? DeclaratorContext::AliasTemplate
: DeclaratorContext::AliasDecl,
AS, &DeclFromDeclSpec, &Attrs);
+
+ this->TemplateParamsFromAlias = nullptr;
+
if (OwnedType)
*OwnedType = DeclFromDeclSpec;
@@ -2173,6 +2179,17 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
assert(Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
isClassCompatibleKeyword());
+
+ if (TemplateParamsFromAlias) {
+ for (const TemplateParameterList *TPL : *TemplateParamsFromAlias) {
+ for (NamedDecl *D : *TPL) {
+ D->setInvalidDecl(true);
+ auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D);
+ TTPD->setTypeForDecl(Actions.Context.IntTy.getTypePtr());
+ }
+ }
+ }
+
if (SkipBody.ShouldSkip)
SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
TagOrTempResult.get());
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 1c654f46e23b3..c6a54dc141ded 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -220,14 +220,6 @@ static ExprResult EvaluateAtomicConstraint(
if (Inst.isInvalid())
return ExprError();
- if (const TemplateTypeParmType *TTPT =
- dyn_cast<TemplateTypeParmType>(AtomicExpr->getType().getDesugaredType(S.Context))) {
- TemplateTypeParmDecl *TTPD = TTPT->getDecl();
- if (TTPD->isInvalidDecl()) {
- return ExprError();
- }
- }
-
llvm::FoldingSetNodeID ID;
if (Template &&
DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 86b871396ec90..50c09bd3cdea7 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -288,8 +288,8 @@ static ParsedType buildNamedType(Sema &S, const CXXScopeSpec *SS, QualType T,
case Type::ObjCTypeParam:
case Type::TemplateTypeParm:
return ParsedType::make(T);
- default:
- llvm_unreachable("Unexpected Type Class");
+ //default:
+ //llvm_unreachable("Unexpected Type Class");
}
if (!SS || SS->isEmpty())
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3efd18c0dcd96..55e078f3180a2 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13717,15 +13717,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
const ParsedAttributesView &AttrList,
TypeResult Type, Decl *DeclFromDeclSpec) {
- if (Type.isInvalid()) {
- for (TemplateParameterList *TPL : TemplateParamLists) {
- for (NamedDecl *D : *TPL) {
- D->setInvalidDecl(true);
- }
- }
+ if (Type.isInvalid())
return nullptr;
- }
-
bool Invalid = false;
DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name);
diff --git a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
index af254828b0fe7..fa3eb1372bd3f 100644
--- a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
+++ b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -63,13 +63,13 @@ atomicish<int> f(); // expected-error {{expected 'auto' or 'decltype(auto)' afte
namespace GH91564 {
template <class T> using A = struct B { // expected-error {{'GH91564::B' cannot be defined in a type alias template}}
- template <class> void f() requires (T()); // expected-note {{candidate template ignored: failed template argument deduction}}
+ template <class> void f() requires (T()); // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} expected-note {{explicit instantiation refers here}}
};
-template void B::f<void>(); // expected-error {{explicit instantiation of 'f' does not refer to a function template, variable template, member function, member class, or static data member}}
+template void B::f<void>(); // expected-error {{explicit instantiation of undefined function template 'f'}}
template <class T> using C = struct D { // expected-error {{'GH91564::D' cannot be defined in a type alias template}}
using E = T;
};
-template <class> void g() requires (D::E()); // expected-note {{candidate template ignored: failed template argument deduction}}
-template void g<void>(); // expected-error {{explicit instantiation of 'g' does not refer to a function template, variable template, member function, member class, or static data member}}
+template <class> void g() requires (D::E()); // expected-error {{atomic constraint must be of type 'bool' (found 'D::E' (aka 'int'))}} expected-note {{explicit instantiation refers here}}
+template void g<void>(); // expected-error {{explicit instantiation of undefined function template 'g'}}
}
\ No newline at end of file
More information about the cfe-commits
mailing list