Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang][Parser] Don't evaluate concept when its definition is invalid #111179

Merged
merged 3 commits into from
Oct 10, 2024

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Oct 4, 2024

Since #103867, the nullness of the concept declaration has been turned to represent a state in which the concept definition is being parsed and used for self-reference checking.

However, PR missed a case where such a definition could be invalid, and we shall inhibit them from making it into evaluation.

Fixes #109780

@zyn0217 zyn0217 requested a review from cor3ntin October 4, 2024 15:50
@zyn0217 zyn0217 requested a review from Endilll as a code owner October 4, 2024 15:50
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 4, 2024

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

Changes

Since #103867, the nullness of the concept declaration has been turned to represent a state in which the concept definition is being parsed and used for self-reference checking.

However, that PR missed a case where such a definition could be invalid and thus, the definition should not be found. Otherwise, the assumption in the evaluation would fail. This PR fixes it by removing the definition from the DeclContext in such situations.

Fixes #109780


Full diff: https://github.com/llvm/llvm-project/pull/111179.diff

4 Files Affected:

  • (modified) clang/include/clang/Sema/Sema.h (+1-1)
  • (modified) clang/lib/Parse/ParseTemplate.cpp (+9-1)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+4-2)
  • (modified) clang/test/SemaTemplate/concepts.cpp (+14)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index bede971ce0191b..eea3cf4e43cde8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11995,7 +11995,7 @@ class Sema final : public SemaBase {
 
   ConceptDecl *ActOnStartConceptDefinition(
       Scope *S, MultiTemplateParamsArg TemplateParameterLists,
-      const IdentifierInfo *Name, SourceLocation NameLoc);
+      const IdentifierInfo *Name, SourceLocation NameLoc, bool &AddedToScope);
 
   ConceptDecl *ActOnFinishConceptDefinition(Scope *S, ConceptDecl *C,
                                             Expr *ConstraintExpr,
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index de29652abbfd95..9ddabdf5172e41 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -322,13 +322,19 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
 
   // [C++26][basic.scope.pdecl]/p13
   // The locus of a concept-definition is immediately after its concept-name.
+  bool AddedToScope = false;
   ConceptDecl *D = Actions.ActOnStartConceptDefinition(
-      getCurScope(), *TemplateInfo.TemplateParams, Id, IdLoc);
+      getCurScope(), *TemplateInfo.TemplateParams, Id, IdLoc, AddedToScope);
 
   ParsedAttributes Attrs(AttrFactory);
   MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);
 
   if (!TryConsumeToken(tok::equal)) {
+    // The expression is unset until ActOnFinishConceptDefinition(), so remove
+    // the invalid declaration from the future lookup such that the evaluation
+    // wouldn't have to handle empty expressions.
+    if (AddedToScope)
+      Actions.CurContext->removeDecl(D);
     Diag(Tok.getLocation(), diag::err_expected) << tok::equal;
     SkipUntil(tok::semi);
     return nullptr;
@@ -337,6 +343,8 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
   ExprResult ConstraintExprResult =
       Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
   if (ConstraintExprResult.isInvalid()) {
+    if (AddedToScope)
+      Actions.CurContext->removeDecl(D);
     SkipUntil(tok::semi);
     return nullptr;
   }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index eeaa1ebd7ba83a..2d8b47ea2474be 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -8632,7 +8632,7 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
 
 ConceptDecl *Sema::ActOnStartConceptDefinition(
     Scope *S, MultiTemplateParamsArg TemplateParameterLists,
-    const IdentifierInfo *Name, SourceLocation NameLoc) {
+    const IdentifierInfo *Name, SourceLocation NameLoc, bool &AddedToScope) {
   DeclContext *DC = CurContext;
 
   if (!DC->getRedeclContext()->isFileContext()) {
@@ -8688,8 +8688,10 @@ ConceptDecl *Sema::ActOnStartConceptDefinition(
   // We cannot properly handle redeclarations until we parse the constraint
   // expression, so only inject the name if we are sure we are not redeclaring a
   // symbol
-  if (Previous.empty())
+  if (Previous.empty()) {
     PushOnScopeChains(NewDecl, S, true);
+    AddedToScope = true;
+  }
 
   return NewDecl;
 }
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index a98ca3939222bd..9d29cc59d3ab96 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1151,3 +1151,17 @@ int test() {
 }
 
 }
+
+namespace GH109780 {
+
+template <typename T>
+concept Concept; // expected-error {{expected '='}}
+
+bool val = Concept<int>; // expected-error {{use of undeclared identifier 'Concept'}}
+
+template <typename T>
+concept C = invalid; // expected-error {{use of undeclared identifier 'invalid'}}
+
+bool val2 = C<int>; // expected-error {{use of undeclared identifier 'C'}}
+
+} // namespace GH109780

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zyn0217 zyn0217 changed the title [Clang][Parser] Remove the concept from the DeclContext if the definition is invalid [Clang][Parser] Don't evaluate concept when its definition is invalid Oct 7, 2024
@zyn0217 zyn0217 merged commit 03229e7 into llvm:main Oct 10, 2024
9 checks passed
@zyn0217 zyn0217 deleted the 109780 branch October 10, 2024 01:36
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
…llvm#111179)

Since llvm#103867, the nullness of the concept declaration has been turned
to represent a state in which the concept definition is being parsed and
used for self-reference checking.

However, PR missed a case where such a definition could be invalid, and
we shall inhibit making it into evaluation.

Fixes llvm#109780
falbrechtskirchinger added a commit to falbrechtskirchinger/llvm-project that referenced this pull request Oct 21, 2024
The ASTWriter currently assumes template type constraints to be
initialized ((bool)getTypeConstraint() == hasTypeConstraint()).
The attached test case presents a scenario where that doesn't apply, and
is a regression test for issues llvm#99036 and llvm#109354.

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 llvm#111179.
falbrechtskirchinger added a commit to falbrechtskirchinger/llvm-project that referenced this pull request Oct 21, 2024
The ASTWriter currently assumes template type constraints to be
initialized ((bool)getTypeConstraint() == hasTypeConstraint()). Issues
llvm#99036 and llvm#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 llvm#111179.
This solution avoids backporting llvm#111179 and its dependencies.
tru pushed a commit to falbrechtskirchinger/llvm-project that referenced this pull request Oct 29, 2024
The ASTWriter currently assumes template type constraints to be
initialized ((bool)getTypeConstraint() == hasTypeConstraint()). Issues
llvm#99036 and llvm#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 llvm#111179.
This solution avoids backporting llvm#111179 and its dependencies.
@shafik
Copy link
Collaborator

shafik commented Nov 6, 2024

This crash looks linked to this change: #115004

@shafik
Copy link
Collaborator

shafik commented Jan 8, 2025

This crash looks linked to this change: #121980

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

clang 20 crashes on invalid input
4 participants