forked from OSchip/llvm-project
[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:
parent
ee599bf2a9
commit
70d9dc8674
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}}
|
||||||
|
}
|
Loading…
Reference in New Issue