Author: Haojian Wu Date: 2020-12-11T10:38:03+01:00 New Revision: 556e4eba4404acdc003ce344a62de846c0661be2
URL: https://github.com/llvm/llvm-project/commit/556e4eba4404acdc003ce344a62de846c0661be2 DIFF: https://github.com/llvm/llvm-project/commit/556e4eba4404acdc003ce344a62de846c0661be2.diff LOG: [AST][RecoveryAST] Preserve type for member call expr if argments are not matched. Differential Revision: https://reviews.llvm.org/D92298 Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaOverload.cpp clang/test/AST/ast-dump-recovery.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9c838e574283..04e2b9553f4c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3723,11 +3723,11 @@ class Sema final { SourceLocation RLoc, Expr *Base,Expr *Idx); - ExprResult - BuildCallToMemberFunction(Scope *S, Expr *MemExpr, - SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation RParenLoc); + ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc, + bool AllowRecovery = false); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, MultiExprArg Args, @@ -5238,7 +5238,8 @@ class Sema final { ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, - bool IsExecConfig = false); + bool IsExecConfig = false, + bool AllowRecovery = false); enum class AtomicArgumentOrder { API, AST }; ExprResult BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 859960d13007..0e829230d6a8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6309,7 +6309,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig) { ExprResult Call = - BuildCallExpr(Scope, Fn, LParenLoc, ArgExprs, RParenLoc, ExecConfig); + BuildCallExpr(Scope, Fn, LParenLoc, ArgExprs, RParenLoc, ExecConfig, + /*IsExecConfig=*/false, /*AllowRecovery=*/true); if (Call.isInvalid()) return Call; @@ -6337,7 +6338,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, /// locations. ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, - Expr *ExecConfig, bool IsExecConfig) { + Expr *ExecConfig, bool IsExecConfig, + bool AllowRecovery) { // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(Scope, Fn); if (Result.isInvalid()) return ExprError(); @@ -6397,7 +6399,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.BoundMemberTy) { return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, - RParenLoc); + RParenLoc, AllowRecovery); } } @@ -6416,7 +6418,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, Scope, Fn, ULE, LParenLoc, ArgExprs, RParenLoc, ExecConfig, /*AllowTypoCorrection=*/true, find.IsAddressOfOperand); return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, - RParenLoc); + RParenLoc, AllowRecovery); } } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index ff010fd6e4df..5689efe578fa 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14154,11 +14154,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// parameter). The caller needs to validate that the member /// expression refers to a non-static member function or an overloaded /// member function. -ExprResult -Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, - SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation RParenLoc) { +ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc, + bool AllowRecovery) { assert(MemExprE->getType() == Context.BoundMemberTy || MemExprE->getType() == Context.OverloadTy); @@ -14215,6 +14215,17 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return MaybeBindToTemporary(call); } + // We only try to build a recovery expr at this level if we can preserve + // the return type, otherwise we return ExprError() and let the caller + // recover. + auto BuildRecoveryExpr = [&](QualType Type) { + if (!AllowRecovery) + return ExprError(); + std::vector<Expr *> SubExprs = {MemExprE}; + llvm::for_each(Args, [&SubExprs](Expr *E) { SubExprs.push_back(E); }); + return CreateRecoveryExpr(MemExprE->getBeginLoc(), RParenLoc, SubExprs, + Type); + }; if (isa<CXXPseudoDestructorExpr>(NakedMemExpr)) return CallExpr::Create(Context, MemExprE, Args, Context.VoidTy, VK_RValue, RParenLoc, CurFPFeatureOverrides()); @@ -14362,7 +14373,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Check for a valid return type. if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(), TheCall, Method)) - return ExprError(); + return BuildRecoveryExpr(ResultType); // Convert the object argument (for a non-static member function call). // We only need to do this if there was actually an overload; otherwise @@ -14379,7 +14390,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Convert the rest of the arguments if (ConvertArgumentsForCall(TheCall, MemExpr, Method, Proto, Args, RParenLoc)) - return ExprError(); + return BuildRecoveryExpr(ResultType); DiagnoseSentinelCalls(Method, LParenLoc, Args); diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index 366b3bfd9e07..2a8346eb0d15 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -121,6 +121,23 @@ void test(int x) { foo->func(x); } +struct Foo2 { + double func(); + class ForwardClass; + ForwardClass createFwd(); +}; +void test2(Foo2 f) { + // CHECK: RecoveryExpr {{.*}} 'double' + // CHECK-NEXT: |-MemberExpr {{.*}} '<bound member function type>' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'f' + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 + f.func(1); + // CHECK: RecoveryExpr {{.*}} 'Foo2::ForwardClass' + // CHECK-NEXT: `-MemberExpr {{.*}} '<bound member function type>' .createFwd + // CHECK-NEXT: `-DeclRefExpr {{.*}} 'f' + f.createFwd(); +} + // CHECK: |-AlignedAttr {{.*}} alignas // CHECK-NEXT:| `-RecoveryExpr {{.*}} contains-errors // CHECK-NEXT:| `-UnresolvedLookupExpr {{.*}} 'invalid' _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits