[AST][RecoveryExpr] Fix the value category for recovery expr.

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
This commit is contained in:
Haojian Wu 2020-07-08 13:53:47 +02:00
parent 695b33a569
commit 96a5cfff20
5 changed files with 25 additions and 6 deletions

View File

@ -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; }));

View File

@ -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:
@ -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());

View File

@ -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)

View File

@ -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
@ -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
@ -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.
}

View File

@ -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}}
}