Skip to content

Commit 2fd01d7

Browse files
committed
[clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure
We're expecting a SubstitutionDiagnostic in diagnoseUnsatisfiedRequirement if the status of ExprRequirement is SubstFailure. Previously, the Requirement was created with Expr on SubstFailure by mistake, which could lead to the assertion failure in the subsequent diagnosis. Fixes clangd/clangd#1726 Fixes #64723 Fixes #64172 In addition, this patch also fixes an invalid test from D129499. Reviewed By: erichkeane Differential Revision: https://reviews.llvm.org/D158061
1 parent 777e268 commit 2fd01d7

File tree

6 files changed

+85
-16
lines changed

6 files changed

+85
-16
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ Bug Fixes to C++ Support
250250
(`#64962 <https://github.com/llvm/llvm-project/issues/64962>`_) and
251251
(`#28679 <https://github.com/llvm/llvm-project/issues/28679>`_).
252252

253+
- Fix a crash caused by substitution failure in expression requirements.
254+
(`#64172 <https://github.com/llvm/llvm-project/issues/64172>`_) and
255+
(`#64723 <https://github.com/llvm/llvm-project/issues/64723>`_).
256+
253257
Bug Fixes to AST Handling
254258
^^^^^^^^^^^^^^^^^^^^^^^^^
255259
- Fixed an import failure of recursive friend class template.

clang/include/clang/AST/ExprConcepts.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,21 @@
1414
#ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
1515
#define LLVM_CLANG_AST_EXPRCONCEPTS_H
1616

17-
#include "clang/AST/ASTContext.h"
1817
#include "clang/AST/ASTConcept.h"
18+
#include "clang/AST/ASTContext.h"
1919
#include "clang/AST/Decl.h"
20-
#include "clang/AST/DeclarationName.h"
2120
#include "clang/AST/DeclTemplate.h"
21+
#include "clang/AST/DeclarationName.h"
2222
#include "clang/AST/Expr.h"
2323
#include "clang/AST/NestedNameSpecifier.h"
2424
#include "clang/AST/TemplateBase.h"
2525
#include "clang/AST/Type.h"
2626
#include "clang/Basic/SourceLocation.h"
27+
#include "llvm/ADT/STLFunctionalExtras.h"
2728
#include "llvm/Support/ErrorHandling.h"
2829
#include "llvm/Support/TrailingObjects.h"
29-
#include <utility>
3030
#include <string>
31+
#include <utility>
3132

3233
namespace clang {
3334
class ASTStmtReader;
@@ -486,6 +487,13 @@ class NestedRequirement : public Requirement {
486487
}
487488
};
488489

490+
using EntityPrinter = llvm::function_ref<void(llvm::raw_ostream &)>;
491+
492+
/// \brief create a Requirement::SubstitutionDiagnostic with only a
493+
/// SubstitutedEntity and DiagLoc using Sema's allocator.
494+
Requirement::SubstitutionDiagnostic *
495+
createSubstDiagAt(Sema &S, SourceLocation Location, EntityPrinter Printer);
496+
489497
} // namespace concepts
490498

491499
/// C++2a [expr.prim.req]:

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/AST/CharUnits.h"
2020
#include "clang/AST/DeclObjC.h"
2121
#include "clang/AST/ExprCXX.h"
22+
#include "clang/AST/ExprConcepts.h"
2223
#include "clang/AST/ExprObjC.h"
2324
#include "clang/AST/RecursiveASTVisitor.h"
2425
#include "clang/AST/Type.h"
@@ -9080,16 +9081,22 @@ Sema::BuildExprRequirement(
90809081
MLTAL.addOuterRetainedLevels(TPL->getDepth());
90819082
const TypeConstraint *TC = Param->getTypeConstraint();
90829083
assert(TC && "Type Constraint cannot be null here");
9083-
ExprResult Constraint =
9084-
SubstExpr(TC->getImmediatelyDeclaredConstraint(), MLTAL);
9084+
auto *IDC = TC->getImmediatelyDeclaredConstraint();
9085+
assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
9086+
ExprResult Constraint = SubstExpr(IDC, MLTAL);
90859087
if (Constraint.isInvalid()) {
9086-
Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
9087-
} else {
9088-
SubstitutedConstraintExpr =
9089-
cast<ConceptSpecializationExpr>(Constraint.get());
9090-
if (!SubstitutedConstraintExpr->isSatisfied())
9091-
Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
9092-
}
9088+
return new (Context) concepts::ExprRequirement(
9089+
concepts::createSubstDiagAt(*this, IDC->getExprLoc(),
9090+
[&](llvm::raw_ostream &OS) {
9091+
IDC->printPretty(OS, /*Helper=*/nullptr,
9092+
getPrintingPolicy());
9093+
}),
9094+
IsSimple, NoexceptLoc, ReturnTypeRequirement);
9095+
}
9096+
SubstitutedConstraintExpr =
9097+
cast<ConceptSpecializationExpr>(Constraint.get());
9098+
if (!SubstitutedConstraintExpr->isSatisfied())
9099+
Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
90939100
}
90949101
return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc,
90959102
ReturnTypeRequirement, Status,

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,9 +2271,9 @@ QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
22712271
getPackIndex(Pack), Arg, TL.getNameLoc());
22722272
}
22732273

2274-
template<typename EntityPrinter>
22752274
static concepts::Requirement::SubstitutionDiagnostic *
2276-
createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
2275+
createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
2276+
concepts::EntityPrinter Printer) {
22772277
SmallString<128> Message;
22782278
SourceLocation ErrorLoc;
22792279
if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
22972297
StringRef(MessageBuf, Message.size())};
22982298
}
22992299

2300+
concepts::Requirement::SubstitutionDiagnostic *
2301+
concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
2302+
EntityPrinter Printer) {
2303+
SmallString<128> Entity;
2304+
llvm::raw_svector_ostream OS(Entity);
2305+
Printer(OS);
2306+
char *EntityBuf = new (S.Context) char[Entity.size()];
2307+
llvm::copy(Entity, EntityBuf);
2308+
return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
2309+
/*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
2310+
/*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
2311+
}
2312+
23002313
ExprResult TemplateInstantiator::TransformRequiresTypeParams(
23012314
SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
23022315
RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
2+
3+
template <typename Iterator> class normal_iterator {};
4+
5+
template <typename From, typename To> struct is_convertible {};
6+
7+
template <typename From, typename To>
8+
inline constexpr bool is_convertible_v = is_convertible<From, To>::value; // expected-error {{no member named 'value' in 'is_convertible<bool, bool>'}}
9+
10+
template <typename From, typename To>
11+
concept convertible_to = is_convertible_v<From, To>; // #1
12+
13+
template <typename IteratorL, typename IteratorR>
14+
requires requires(IteratorL lhs, IteratorR rhs) { // #2
15+
{ lhs == rhs } -> convertible_to<bool>; // #3
16+
}
17+
constexpr bool compare(normal_iterator<IteratorL> lhs, normal_iterator<IteratorR> rhs) { // #4
18+
return false;
19+
}
20+
21+
class Object;
22+
23+
void function() {
24+
normal_iterator<Object *> begin, end;
25+
compare(begin, end); // expected-error {{no matching function for call to 'compare'}} #5
26+
}
27+
28+
// expected-note@#1 {{in instantiation of variable template specialization 'is_convertible_v<bool, bool>' requested here}}
29+
// expected-note@#1 {{substituting template arguments into constraint expression here}}
30+
// expected-note@#3 {{checking the satisfaction of concept 'convertible_to<bool, bool>'}}
31+
// expected-note@#2 {{substituting template arguments into constraint expression here}}
32+
// expected-note@#5 {{checking constraint satisfaction for template 'compare<Object *, Object *>'}}
33+
// expected-note@#5 {{in instantiation of function template specialization 'compare<Object *, Object *>' requested here}}
34+
35+
// expected-note@#4 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
36+
// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
37+
// expected-note@#3 {{because 'convertible_to<expr-type, bool>' would be invalid}}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
22

33
template <class>
44
concept f = requires { 42; };
55
struct h {
66
// The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
77
// We test that we do not crash in such cases (#55401)
88
int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
9-
// expected-error@* {{too many errros emitted}}
9+
// expected-error@* {{too many errors emitted}}
1010
};

0 commit comments

Comments
 (0)