Skip to content

Commit 925e195

Browse files
authored
[Clang] enhance error recovery with RecoveryExpr for trailing commas in call arguments (llvm#114684)
Fixes llvm#100921
1 parent 994c544 commit 925e195

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,8 @@ Improvements to Clang's diagnostics
578578

579579
- Clang now omits shadowing warnings for parameter names in explicit object member functions (#GH95707).
580580

581+
- Improved error recovery for function call arguments with trailing commas (#GH100921).
582+
581583
Improvements to Clang's time-trace
582584
----------------------------------
583585

clang/include/clang/Parse/Parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1934,7 +1934,8 @@ class Parser : public CodeCompletionHandler {
19341934
llvm::function_ref<void()> ExpressionStarts =
19351935
llvm::function_ref<void()>(),
19361936
bool FailImmediatelyOnInvalidExpr = false,
1937-
bool EarlyTypoCorrection = false);
1937+
bool EarlyTypoCorrection = false,
1938+
bool *HasTrailingComma = nullptr);
19381939

19391940
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
19401941
/// used for misc language extensions.

clang/lib/Parse/ParseExpr.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,10 +2199,17 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
21992199
};
22002200
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
22012201
if (Tok.isNot(tok::r_paren)) {
2202-
if (ParseExpressionList(ArgExprs, [&] {
2202+
bool HasTrailingComma = false;
2203+
bool HasError = ParseExpressionList(
2204+
ArgExprs,
2205+
[&] {
22032206
PreferredType.enterFunctionArgument(Tok.getLocation(),
22042207
RunSignatureHelp);
2205-
})) {
2208+
},
2209+
/*FailImmediatelyOnInvalidExpr*/ false,
2210+
/*EarlyTypoCorrection*/ false, &HasTrailingComma);
2211+
2212+
if (HasError && !HasTrailingComma) {
22062213
(void)Actions.CorrectDelayedTyposInExpr(LHS);
22072214
// If we got an error when parsing expression list, we don't call
22082215
// the CodeCompleteCall handler inside the parser. So call it here
@@ -3662,7 +3669,8 @@ void Parser::injectEmbedTokens() {
36623669
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
36633670
llvm::function_ref<void()> ExpressionStarts,
36643671
bool FailImmediatelyOnInvalidExpr,
3665-
bool EarlyTypoCorrection) {
3672+
bool EarlyTypoCorrection,
3673+
bool *HasTrailingComma) {
36663674
bool SawError = false;
36673675
while (true) {
36683676
if (ExpressionStarts)
@@ -3705,6 +3713,12 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
37053713
Token Comma = Tok;
37063714
ConsumeToken();
37073715
checkPotentialAngleBracketDelimiter(Comma);
3716+
3717+
if (Tok.is(tok::r_paren)) {
3718+
if (HasTrailingComma)
3719+
*HasTrailingComma = true;
3720+
break;
3721+
}
37083722
}
37093723
if (SawError) {
37103724
// Ensure typos get diagnosed when errors were encountered while parsing the

clang/test/AST/ast-dump-recovery.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ int some_func(int *);
99
// CHECK-NEXT: `-IntegerLiteral {{.*}} 123
1010
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
1111
int invalid_call = some_func(123);
12-
void test_invalid_call(int s) {
12+
void test_invalid_call_1(int s) {
1313
// CHECK: CallExpr {{.*}} '<dependent type>' contains-errors
1414
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
1515
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:13>
@@ -32,6 +32,26 @@ void test_invalid_call(int s) {
3232
int var = some_func(undef1);
3333
}
3434

35+
int some_func2(int a, int b);
36+
void test_invalid_call_2() {
37+
// CHECK: -RecoveryExpr {{.*}} 'int' contains-errors
38+
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} '<overloaded function type>' lvalue (ADL) = 'some_func2'
39+
some_func2(,);
40+
41+
// CHECK: -RecoveryExpr {{.*}} 'int' contains-errors
42+
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} '<overloaded function type>' lvalue (ADL) = 'some_func2'
43+
some_func2(,,);
44+
45+
// CHECK: `-RecoveryExpr {{.*}} 'int' contains-errors
46+
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} '<overloaded function type>' lvalue (ADL) = 'some_func2'
47+
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
48+
some_func2(1,);
49+
50+
// FIXME: Handle invalid argument with recovery
51+
// CHECK-NOT: `-RecoveryExpr
52+
some_func2(,1);
53+
}
54+
3555
int ambig_func(double);
3656
int ambig_func(float);
3757

0 commit comments

Comments
 (0)