From 312776183068b84ddfea38ea7158c44c1926160a Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Wed, 8 Jan 2025 15:40:23 +0800 Subject: [PATCH 1/3] [Clang] Don't form a type constraint if the concept is invalid After 0dedd6fe1 and 03229e7c0, invalid concept declarations might lack expressions for evaluation and normalization. This could make it crash in certain scenarios, apart from the one of evaluation concepts showed in 03229e7c0, there's also an issue when checking specializations where the normalization also relies on a non-null expression. This patch prevents that by avoiding building up a type constraint in such situations, thereafter the template parameter wouldn't have a concept specialization of a null expression. With this patch, the assumption in ASTWriterDecl is no longer valid. Namely, HasConstraint and TypeConstraintInitialized must now represent different meanings for both source fidelity and semantic requirements. --- clang/lib/Sema/SemaTemplate.cpp | 3 +++ clang/lib/Serialization/ASTWriterDecl.cpp | 1 - clang/test/SemaTemplate/concepts.cpp | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 20ec2fbeaa6a8bb..ce672b00893b0df 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4557,6 +4557,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { assert(NamedConcept && "A concept template id without a template?"); + if (NamedConcept->isInvalidDecl()) + return ExprError(); + llvm::SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( NamedConcept, ConceptNameInfo.getLoc(), diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 75c1d9a6d438ce5..c7b8759916f421a 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1951,7 +1951,6 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { Record.push_back(D->wasDeclaredWithTypename()); const TypeConstraint *TC = D->getTypeConstraint(); - assert((bool)TC == D->hasTypeConstraint()); if (TC) { auto *CR = TC->getConceptReference(); Record.push_back(CR != nullptr); diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 312469313fc5358..f335ca3bd22bc32 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1165,3 +1165,15 @@ concept C = invalid; // expected-error {{use of undeclared identifier 'invalid'} bool val2 = C; } // namespace GH109780 + +namespace GH121980 { + +template +concept has_member_difference_type; // expected-error {{expected '='}} + +template struct incrementable_traits; // expected-note {{declared here}} + +template +struct incrementable_traits; // expected-error {{not more specialized than the primary}} + +} From 202196262cc0864b9cbeb91ea6df6e0cd299fe5d Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Wed, 8 Jan 2025 18:43:02 +0800 Subject: [PATCH 2/3] Fix the serialization for invalid constraints --- clang/lib/Serialization/ASTReaderDecl.cpp | 6 +++++- clang/lib/Serialization/ASTWriterDecl.cpp | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 719bc0d06f5b11a..9671492f0d65449 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2663,7 +2663,11 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { D->setDeclaredWithTypename(Record.readInt()); - if (D->hasTypeConstraint()) { + bool TypeConstraintInitialized = false; + if (D->hasTypeConstraint()) + TypeConstraintInitialized = Record.readBool(); + + if (D->hasTypeConstraint() && TypeConstraintInitialized) { ConceptReference *CR = nullptr; if (Record.readBool()) CR = Record.readConceptReference(); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c7b8759916f421a..f8ed155ca389d7f 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1951,6 +1951,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { Record.push_back(D->wasDeclaredWithTypename()); const TypeConstraint *TC = D->getTypeConstraint(); + if (D->hasTypeConstraint()) + Record.push_back(/*TypeConstraintInitialized=*/TC != nullptr); if (TC) { auto *CR = TC->getConceptReference(); Record.push_back(CR != nullptr); @@ -1968,7 +1970,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { if (OwnsDefaultArg) Record.AddTemplateArgumentLoc(D->getDefaultArgument()); - if (!TC && !OwnsDefaultArg && + if (!D->hasTypeConstraint() && !OwnsDefaultArg && D->getDeclContext() == D->getLexicalDeclContext() && !D->isInvalidDecl() && !D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() && !D->isImplicit() && From 6b59c7a8c8a5d06208e49622d68dd671032ed951 Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Wed, 8 Jan 2025 18:48:39 +0800 Subject: [PATCH 3/3] fixup! Fix the serialization for invalid constraints --- clang/lib/Serialization/ASTReaderDecl.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 9671492f0d65449..8c60e85c93d70e2 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2663,11 +2663,8 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { D->setDeclaredWithTypename(Record.readInt()); - bool TypeConstraintInitialized = false; - if (D->hasTypeConstraint()) - TypeConstraintInitialized = Record.readBool(); - - if (D->hasTypeConstraint() && TypeConstraintInitialized) { + bool TypeConstraintInitialized = D->hasTypeConstraint() && Record.readBool(); + if (TypeConstraintInitialized) { ConceptReference *CR = nullptr; if (Record.readBool()) CR = Record.readConceptReference();