[AST][RecoveryExpr] Support dependent binary operator in C for error recovery.

see the whole context in:  https://reviews.llvm.org/D85025

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D84226
This commit is contained in:
Haojian Wu 2020-10-06 08:51:49 +02:00
parent ee599bf2a9
commit 70d9dc8674
4 changed files with 88 additions and 7 deletions

View File

@ -665,6 +665,14 @@ public:
const LangOptions& getLangOpts() const { return LangOpts; } const LangOptions& getLangOpts() const { return LangOpts; }
// If this condition is false, typo correction must be performed eagerly
// rather than delayed in many places, as it makes use of dependent types.
// the condition is false for clang's C-only codepath, as it doesn't support
// dependent types yet.
bool isDependenceAllowed() const {
return LangOpts.CPlusPlus || LangOpts.RecoveryAST;
}
const SanitizerBlacklist &getSanitizerBlacklist() const { const SanitizerBlacklist &getSanitizerBlacklist() const {
return *SanitizerBL; return *SanitizerBL;
} }

View File

@ -24,6 +24,7 @@
#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h" #include "clang/AST/ExprOpenMP.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h" #include "clang/Basic/Builtins.h"
@ -13683,7 +13684,7 @@ static std::pair<ExprResult, ExprResult>
CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
Expr *RHSExpr) { Expr *RHSExpr) {
ExprResult LHS = LHSExpr, RHS = RHSExpr; ExprResult LHS = LHSExpr, RHS = RHSExpr;
if (!S.getLangOpts().CPlusPlus) { if (!S.Context.isDependenceAllowed()) {
// C cannot handle TypoExpr nodes on either side of a binop because it // 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 // doesn't handle dependent types properly, so make sure any TypoExprs have
// been dealt with before checking the operands. // been dealt with before checking the operands.
@ -14364,6 +14365,47 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); 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))
// C [6.15.16] p3:
// An assignment expression has the value of the left operand after the
// assignment, but is not an lvalue.
return CompoundAssignOperator::Create(
Context, LHSExpr, RHSExpr, Opc,
LHSExpr->getType().getUnqualifiedType(), VK_RValue, OK_Ordinary,
OpLoc, CurFPFeatureOverrides());
QualType ResultType;
switch (Opc) {
case BO_Assign:
ResultType = LHSExpr->getType().getUnqualifiedType();
break;
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.
ResultType = Context.IntTy;
break;
case BO_Comma:
ResultType = RHSExpr->getType();
break;
default:
ResultType = Context.DependentTy;
break;
}
return BinaryOperator::Create(Context, LHSExpr, RHSExpr, Opc, ResultType,
VK_RValue, OK_Ordinary, OpLoc,
CurFPFeatureOverrides());
}
// Build a built-in binary operation. // Build a built-in binary operation.
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
} }

View File

@ -42,11 +42,33 @@ void test1() {
void test2() { void test2() {
int* ptr; int* ptr;
// FIXME: the top-level expr should be a binary operator. // CHECK: BinaryOperator {{.*}} 'int *' contains-errors '='
// CHECK: ImplicitCastExpr {{.*}} contains-errors <LValueToRValue> // CHECK-NEXT: |-DeclRefExpr {{.*}} 'ptr' 'int *'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors lvalue // CHECK-NEXT: `-RecoveryExpr {{.*}}
// CHECK-NEXT: |-DeclRefExpr {{.*}} 'ptr' 'int *' // CHECK-NEXT: `-DeclRefExpr {{.*}} 'some_func'
// CHECK-NEXT: `-RecoveryExpr {{.*}}
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'some_func'
ptr = some_func(); // should not crash ptr = some_func(); // should not crash
int compoundOp;
// CHECK: CompoundAssignOperator {{.*}} 'int' contains-errors '+='
// 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;
// CHECK: BinaryOperator {{.*}} '<dependent type>' contains-errors ','
// CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1
// CHECK-NEXT: `-RecoveryExpr {{.*}}
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'some_func'
1, some_func();
// CHECK: BinaryOperator {{.*}} 'int' contains-errors ','
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'some_func'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
some_func(), 1;
} }

View File

@ -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 '<dependent type>'" is
// not emitted.
s = call(); // expected-error {{too few arguments to function call}}
}