Skip to content

Commit

Permalink
[Serialization] Handle uninitialized type constraints
Browse files Browse the repository at this point in the history
The ASTWriter currently assumes template type constraints to be
initialized ((bool)getTypeConstraint() == hasTypeConstraint()). Issues
#99036 and #109354 identified a scenario where this assertion is
violated.

This patch removes the assumption and adds another boolean to the
serialization, to explicitly encode whether the type constraint has been
initialized.

The same issue was incidentally fixed on the main branch by #111179.
This solution avoids backporting #111179 and its dependencies.
  • Loading branch information
falbrechtskirchinger authored and tru committed Oct 29, 2024
1 parent e541aa5 commit ab51ecc
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 7 deletions.
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2665,7 +2665,8 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {

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

if (D->hasTypeConstraint()) {
const bool TypeConstraintInitialized = Record.readBool();
if (TypeConstraintInitialized && D->hasTypeConstraint()) {
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 @@ -1880,7 +1880,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
Record.push_back(D->wasDeclaredWithTypename());

const TypeConstraint *TC = D->getTypeConstraint();
assert((bool)TC == D->hasTypeConstraint());
Record.push_back(/*TypeConstraintInitialized=*/TC != nullptr);
if (TC) {
auto *CR = TC->getConceptReference();
Record.push_back(CR != nullptr);
Expand All @@ -1898,7 +1898,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 Expand Up @@ -2561,6 +2561,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// TemplateTypeParmDecl
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // wasDeclaredWithTypename
Abv->Add(BitCodeAbbrevOp(0)); // TypeConstraintInitialized
Abv->Add(BitCodeAbbrevOp(0)); // OwnsDefaultArg
DeclTemplateTypeParmAbbrev = Stream.EmitAbbrev(std::move(Abv));

Expand Down
15 changes: 11 additions & 4 deletions clang/test/PCH/cxx2a-constraints-crash.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s

// expected-no-diagnostics
// RUN: %clang_cc1 -std=c++2a -fallow-pch-with-compiler-errors -emit-pch -o %t %s -verify
// RUN: %clang_cc1 -std=c++2a -fallow-pch-with-compiler-errors -include-pch %t %s -verify

#ifndef HEADER
#define HEADER
Expand All @@ -27,3 +25,12 @@ int main() {
}

#endif

namespace GH99036 {

template <typename T>
concept C; // expected-error {{expected '='}}

template <C U> void f(); // expected-error {{unknown type name 'C'}}

} // namespace GH99036

0 comments on commit ab51ecc

Please sign in to comment.