Skip to content

Commit

Permalink
[Clang] Don't form a type constraint if the concept is invalid (#122065)
Browse files Browse the repository at this point in the history
After 0dedd6f and 03229e7, 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 03229e7, 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.

Fixes #115004
Fixes #121980
  • Loading branch information
zyn0217 authored Jan 8, 2025
1 parent bfa711a commit edf14ed
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 3 deletions.
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(
NamedConcept, ConceptNameInfo.getLoc(),
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2663,7 +2663,8 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {

D->setDeclaredWithTypename(Record.readInt());

if (D->hasTypeConstraint()) {
bool TypeConstraintInitialized = D->hasTypeConstraint() && Record.readBool();
if (TypeConstraintInitialized) {
ConceptReference *CR = nullptr;
if (Record.readBool())
CR = Record.readConceptReference();
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1951,7 +1951,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
Record.push_back(D->wasDeclaredWithTypename());

const TypeConstraint *TC = D->getTypeConstraint();
assert((bool)TC == D->hasTypeConstraint());
if (D->hasTypeConstraint())
Record.push_back(/*TypeConstraintInitialized=*/TC != nullptr);
if (TC) {
auto *CR = TC->getConceptReference();
Record.push_back(CR != nullptr);
Expand All @@ -1969,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() &&
Expand Down
12 changes: 12 additions & 0 deletions clang/test/SemaTemplate/concepts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1165,3 +1165,15 @@ concept C = invalid; // expected-error {{use of undeclared identifier 'invalid'}
bool val2 = C<int>;

} // namespace GH109780

namespace GH121980 {

template <class>
concept has_member_difference_type; // expected-error {{expected '='}}

template <has_member_difference_type> struct incrementable_traits; // expected-note {{declared here}}

template <has_member_difference_type Tp>
struct incrementable_traits<Tp>; // expected-error {{not more specialized than the primary}}

}

0 comments on commit edf14ed

Please sign in to comment.