diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6228,7 +6228,7 @@ class RecoveryExpr final : public Expr, private llvm::TrailingObjects { public: - static RecoveryExpr *Create(ASTContext &Ctx, QualType T, + static RecoveryExpr *Create(ASTContext &Ctx, QualType T, ExprValueKind VK, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef SubExprs); static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs); @@ -6255,8 +6255,9 @@ } private: - RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, - SourceLocation EndLoc, ArrayRef SubExprs); + RecoveryExpr(ASTContext &Ctx, QualType T, ExprValueKind VK, + SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef SubExprs); RecoveryExpr(EmptyShell Empty, unsigned NumSubExprs) : Expr(RecoveryExprClass, Empty), NumExprs(NumSubExprs) {} diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3952,7 +3952,8 @@ /// Attempts to produce a RecoveryExpr after some AST node cannot be created. ExprResult CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, ArrayRef SubExprs, - QualType T = QualType()); + QualType T = QualType(), + ExprValueKind VK = VK_LValue); ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4777,9 +4777,10 @@ return OriginalTy; } -RecoveryExpr::RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, - SourceLocation EndLoc, ArrayRef SubExprs) - : Expr(RecoveryExprClass, T, VK_LValue, OK_Ordinary), BeginLoc(BeginLoc), +RecoveryExpr::RecoveryExpr(ASTContext &Ctx, QualType T, ExprValueKind VK, + SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef SubExprs) + : Expr(RecoveryExprClass, T, VK, OK_Ordinary), BeginLoc(BeginLoc), EndLoc(EndLoc), NumExprs(SubExprs.size()) { assert(!T.isNull()); assert(llvm::all_of(SubExprs, [](Expr* E) { return E != nullptr; })); @@ -4789,12 +4790,12 @@ } RecoveryExpr *RecoveryExpr::Create(ASTContext &Ctx, QualType T, - SourceLocation BeginLoc, + ExprValueKind VK, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef SubExprs) { void *Mem = Ctx.Allocate(totalSizeToAlloc(SubExprs.size()), alignof(RecoveryExpr)); - return new (Mem) RecoveryExpr(Ctx, T, BeginLoc, EndLoc, SubExprs); + return new (Mem) RecoveryExpr(Ctx, T, VK, BeginLoc, EndLoc, SubExprs); } RecoveryExpr *RecoveryExpr::CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs) { diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -130,7 +130,6 @@ case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: case Expr::TypoExprClass: - case Expr::RecoveryExprClass: case Expr::DependentCoawaitExprClass: case Expr::CXXDependentScopeMemberExprClass: case Expr::DependentScopeDeclRefExprClass: @@ -145,6 +144,9 @@ case Expr::OMPIteratorExprClass: return Cl::CL_LValue; + case Expr::RecoveryExprClass: + return ClassifyExprValueKind(Lang, E, E->getValueKind()); + // C99 6.5.2.5p5 says that compound literals are lvalues. // In C++, they're prvalue temporaries, except for file-scope arrays. case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19209,7 +19209,8 @@ } ExprResult Sema::CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, - ArrayRef SubExprs, QualType T) { + ArrayRef SubExprs, QualType T, + ExprValueKind VK) { // FIXME: enable it for C++, RecoveryExpr is type-dependent to suppress // bogus diagnostics and this trick does not work in C. // FIXME: use containsErrors() to suppress unwanted diags in C. @@ -19219,8 +19220,10 @@ if (isSFINAEContext()) return ExprError(); - if (T.isNull() || !Context.getLangOpts().RecoveryASTType) + if (T.isNull() || !Context.getLangOpts().RecoveryASTType) { // We don't know the concrete type, fallback to dependent type. T = Context.DependentTy; - return RecoveryExpr::Create(Context, T, Begin, End, SubExprs); + VK = VK_LValue; + } + return RecoveryExpr::Create(Context, T, VK, Begin, End, SubExprs); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12818,7 +12818,7 @@ 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) @@ -12938,8 +12938,15 @@ // Overload resolution failed, try to recover. SmallVector SubExprs = {Fn}; SubExprs.append(Args.begin(), Args.end()); - return SemaRef.CreateRecoveryExpr(Fn->getBeginLoc(), RParenLoc, SubExprs, - chooseRecoveryType(*CandidateSet, Best)); + auto ReturnType = chooseRecoveryType(*CandidateSet, Best); + auto Recovery = SemaRef.CreateRecoveryExpr( + Fn->getBeginLoc(), RParenLoc, SubExprs, + ReturnType.isNull() + ? ReturnType + // set the call result type. + : ReturnType.getNonLValueExprType(SemaRef.getASTContext()), + ReturnType.isNull() ? VK_LValue : Expr::getValueKindForType(ReturnType)); + return Recovery; } static void markUnaddressableCandidatesUnviable(Sema &S, diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -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(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 @@ } NoCrashOnInvalidInitList = { .abc = nullptr, }; + +// Verify the value category of recovery expression. +int f1(int); +int& f2(int); +int&& f3(int); +void ValueCategory() { + // CHECK: RecoveryExpr {{.*}} 'int' contains-errors + f1(); // call to a function (nonreference return type) yields a prvalue (not print by default) + // CHECK: RecoveryExpr {{.*}} 'int' contains-errors lvalue + f2(); // call to a function (lvalue reference return type) yields an lvalue. + // CHECK: RecoveryExpr {{.*}} 'int' contains-errors xvalue + f3(); // call to a function (rvalue reference return type) yields an xvalue. +} diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp --- a/clang/test/SemaCXX/recovery-expr-type.cpp +++ b/clang/test/SemaCXX/recovery-expr-type.cpp @@ -62,3 +62,9 @@ // 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}} +}