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 @@ -24,6 +24,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" @@ -13676,7 +13677,7 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { ExprResult LHS = LHSExpr, RHS = RHSExpr; - if (!S.getLangOpts().CPlusPlus) { + if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().RecoveryAST) { // C cannot handle TypoExpr nodes on either side of a binop because it // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. @@ -14356,6 +14357,37 @@ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } + if (getLangOpts().RecoveryAST && + (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())) { + assert(!getLangOpts().CPlusPlus); + assert((LHSExpr->containsErrors() || RHSExpr->containsErrors()) && + "Should only occur in error-recovery path."); + if (BinaryOperator::isCompoundAssignmentOp(Opc)) + return CompoundAssignOperator::Create( + Context, LHSExpr, RHSExpr, Opc, + LHSExpr->getType().getUnqualifiedType(), VK_LValue, OK_Ordinary, + OpLoc, CurFPFeatureOverrides()); + switch (Opc) { + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + + case BO_LAnd: + case BO_LOr: + // These operators have a fixed result type regardless of operands. + return BinaryOperator::Create(Context, LHSExpr, RHSExpr, Opc, + Context.IntTy, VK_RValue, OK_Ordinary, + OpLoc, CurFPFeatureOverrides()); + default: + return BinaryOperator::Create(Context, LHSExpr, RHSExpr, Opc, + Context.DependentTy, VK_RValue, OK_Ordinary, + OpLoc, CurFPFeatureOverrides()); + } + } + // Build a built-in binary operation. return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); } diff --git a/clang/test/AST/ast-dump-recovery.c b/clang/test/AST/ast-dump-recovery.c --- a/clang/test/AST/ast-dump-recovery.c +++ b/clang/test/AST/ast-dump-recovery.c @@ -42,11 +42,22 @@ void test2() { int* ptr; - // FIXME: the top-level expr should be a binary operator. - // CHECK: ImplicitCastExpr {{.*}} contains-errors - // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors lvalue - // CHECK-NEXT: |-DeclRefExpr {{.*}} 'ptr' 'int *' - // CHECK-NEXT: `-RecoveryExpr {{.*}} - // CHECK-NEXT: `-DeclRefExpr {{.*}} 'some_func' + // CHECK: BinaryOperator {{.*}} contains-errors '=' + // CHECK-NEXT: |-DeclRefExpr {{.*}} 'ptr' 'int *' + // CHECK-NEXT: `-RecoveryExpr {{.*}} + // CHECK-NEXT: `-DeclRefExpr {{.*}} 'some_func' ptr = some_func(); // should not crash + + int compoundOp; + // CHECK: CompoundAssignOperator {{.*}} '+=' + // CHECK-NEXT: |-DeclRefExpr {{.*}} 'compoundOp' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-DeclRefExpr {{.*}} 'some_func' + compoundOp += some_func(); + + // CHECK: BinaryOperator {{.*}} 'int' contains-errors '||' + // CHECK-NEXT: |-RecoveryExpr {{.*}} + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'some_func' + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 + some_func() || 1; } diff --git a/clang/test/Sema/error-dependence.c b/clang/test/Sema/error-dependence.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/error-dependence.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -frecovery-ast -fno-recovery-ast-type %s + +int call(int); // expected-note {{'call' declared here}} + +void test1(int s) { + // verify "assigning to 'int' from incompatible type ''" is + // not emitted. + s = call(); // expected-error {{too few arguments to function call}} +}