Skip to content

Commit

Permalink
[AST][RecoveryExpr] Fix the value category for recovery expr.
Browse files Browse the repository at this point in the history
RecoveryExpr was always lvalue, but it is wrong if we use it to model
broken function calls, function call expression has more compliated rules:

- a call to a function whose return type is an lvalue reference yields an lvalue;
- a call to a function whose return type is an rvalue reference yields an xvalue;
- a call to a function whose return type is nonreference type yields a prvalue;

This patch makes the recovery-expr align with the function call if it is
modeled a broken call.

Differential revision: https://reviews.llvm.org/D83201
  • Loading branch information
hokein committed Jul 8, 2020
1 parent 695b33a commit 96a5cff
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 6 deletions.
6 changes: 4 additions & 2 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4779,8 +4779,10 @@ QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) {

RecoveryExpr::RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc,
SourceLocation EndLoc, ArrayRef<Expr *> SubExprs)
: Expr(RecoveryExprClass, T, VK_LValue, OK_Ordinary), BeginLoc(BeginLoc),
EndLoc(EndLoc), NumExprs(SubExprs.size()) {
: Expr(RecoveryExprClass, T.getNonReferenceType(),
T->isDependentType() ? VK_LValue : getValueKindForType(T),
OK_Ordinary),
BeginLoc(BeginLoc), EndLoc(EndLoc), NumExprs(SubExprs.size()) {
assert(!T.isNull());
assert(llvm::all_of(SubExprs, [](Expr* E) { return E != nullptr; }));

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ExprClassification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::TypoExprClass:
case Expr::RecoveryExprClass:
case Expr::DependentCoawaitExprClass:
case Expr::CXXDependentScopeMemberExprClass:
case Expr::DependentScopeDeclRefExprClass:
Expand Down Expand Up @@ -276,6 +275,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return Cl::CL_PRValue;
}

case Expr::RecoveryExprClass:
case Expr::OpaqueValueExprClass:
return ClassifyExprValueKind(Lang, E, E->getValueKind());

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12818,7 +12818,7 @@ static QualType chooseRecoveryType(OverloadCandidateSet &CS,
auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
if (!Candidate.Function)
return;
QualType T = Candidate.Function->getCallResultType();
QualType T = Candidate.Function->getReturnType();
if (T.isNull())
return;
if (!Result)
Expand Down
15 changes: 13 additions & 2 deletions clang/test/AST/ast-dump-recovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
int some_func(int *);

// CHECK: VarDecl {{.*}} invalid_call
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 123
Expand Down Expand Up @@ -34,7 +33,6 @@ int ambig_func(double);
int ambig_func(float);

// CHECK: VarDecl {{.*}} ambig_call
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'ambig_func'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 123
Expand Down Expand Up @@ -211,3 +209,16 @@ struct {
} NoCrashOnInvalidInitList = {
.abc = nullptr,
};

// Verify the value category of recovery expression.
int prvalue(int);
int &lvalue(int);
int &&xvalue(int);
void ValueCategory() {
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors
prvalue(); // call to a function (nonreference return type) yields a prvalue (not print by default)
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors lvalue
lvalue(); // call to a function (lvalue reference return type) yields an lvalue.
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors xvalue
xvalue(); // call to a function (rvalue reference return type) yields an xvalue.
}
6 changes: 6 additions & 0 deletions clang/test/SemaCXX/recovery-expr-type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ constexpr auto x2 = AA<int>::foo2(); // expected-error {{be initialized by a con
// expected-note {{in instantiation of member function}} \
// expected-note {{in call to}}
}

// verify no assertion failure on violating value category.
namespace test4 {
int &&f(int); // expected-note {{candidate function not viable}}
int &&k = f(); // expected-error {{no matching function for call}}
}

0 comments on commit 96a5cff

Please sign in to comment.