// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -fcxx-exceptions -std=gnu++17 -frecovery-ast -frecovery-ast-type -ast-dump %s | FileCheck -strict-whitespace %s
// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -fcxx-exceptions -std=gnu++17 -fno-recovery-ast -ast-dump %s | FileCheck --check-prefix=DISABLED -strict-whitespace %s
int some_func(int *);
// CHECK: VarDecl {{.*}} invalid_call
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 123
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int invalid_call = some_func(123);
void test_invalid_call(int s) {
// CHECK: CallExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:13>
// CHECK-NEXT: `-BinaryOperator {{.*}}
// CHECK-NEXT: |-RecoveryExpr {{.*}}
// CHECK-NEXT: `-IntegerLiteral {{.*}} <col:28> 'int' 1
some_func(undef1, undef2+1);
// CHECK: BinaryOperator {{.*}} '<dependent type>' contains-errors '='
// CHECK-NEXT: |-DeclRefExpr {{.*}} 's'
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
s = some_func(undef1);
// CHECK: VarDecl {{.*}} var 'int'
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
int var = some_func(undef1);
}
int ambig_func(double);
int ambig_func(float);
// CHECK: VarDecl {{.*}} ambig_call
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'ambig_func'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 123
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int ambig_call = ambig_func(123);
// CHECK: VarDecl {{.*}} unresolved_call1
// CHECK-NEXT:`-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'bar'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int unresolved_call1 = bar();
// CHECK: VarDecl {{.*}} unresolved_call2
// CHECK-NEXT:`-CallExpr {{.*}} contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'bar'
// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} 'baz'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'qux'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int unresolved_call2 = bar(baz(), qux());
constexpr int a = 10;
// CHECK: VarDecl {{.*}} postfix_inc
// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'a'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int postfix_inc = a++;
// CHECK: VarDecl {{.*}} prefix_inc
// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'a'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int prefix_inc = ++a;
// CHECK: VarDecl {{.*}} unary_address
// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-ParenExpr {{.*}}
// CHECK-NEXT: `-BinaryOperator {{.*}} '+'
// CHECK-NEXT: |-ImplicitCastExpr
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'a'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int unary_address = &(a + 1);
// CHECK: VarDecl {{.*}} unary_bitinverse
// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-ParenExpr {{.*}}
// CHECK-NEXT: `-BinaryOperator {{.*}} '+'
// CHECK-NEXT: |-ImplicitCastExpr
// CHECK-NEXT: | `-ImplicitCastExpr
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'a'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int unary_bitinverse = ~(a + 0.0);
// CHECK: VarDecl {{.*}} binary
// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: |-DeclRefExpr {{.*}} 'a'
// CHECK-NEXT: `-CXXNullPtrLiteralExpr
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int binary = a + nullptr;
// CHECK: VarDecl {{.*}} ternary
// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: |-DeclRefExpr {{.*}} 'a'
// CHECK-NEXT: |-CXXNullPtrLiteralExpr
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'a'
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
int ternary = a ? nullptr : a;
// CHECK: FunctionDecl
// CHECK-NEXT:|-ParmVarDecl {{.*}} x
// CHECK-NEXT:`-CompoundStmt
// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'foo'
// CHECK-NEXT: `-CallExpr {{.*}} contains-errors
// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'foo'
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x'
struct Foo {} foo;
void test(int x) {
foo.abc;
foo->func(x);
}
void AccessIncompleteClass() {
struct Forward;
Forward* ptr;
// CHECK: CallExpr {{.*}} '<dependent type>'
// CHECK-NEXT: `-CXXDependentScopeMemberExpr {{.*}} '<dependent type>'
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'Forward *'
ptr->method();
}
struct Foo2 {
double func();
class ForwardClass;
ForwardClass createFwd();
int overload();
int overload(int, int);
};
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 {{.*}} 'ForwardClass':'Foo2::ForwardClass'
// CHECK-NEXT: `-MemberExpr {{.*}} '<bound member function type>' .createFwd
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'f'
f.createFwd();
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors
// CHECK-NEXT: |-UnresolvedMemberExpr
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'Foo2'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
f.overload(1);
}
// CHECK: |-AlignedAttr {{.*}} alignas
// CHECK-NEXT:| `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT:| `-UnresolvedLookupExpr {{.*}} 'invalid'
struct alignas(invalid()) Aligned {};
auto f();
int f(double);
// CHECK: VarDecl {{.*}} unknown_type_call 'int'
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
int unknown_type_call = f(0, 0);
void InvalidInitalizer(int x) {
struct Bar { Bar(); };
// CHECK: `-VarDecl {{.*}} a1 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
Bar a1(1);
// CHECK: `-VarDecl {{.*}} a2 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x'
Bar a2(x);
// CHECK: `-VarDecl {{.*}} a3 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-InitListExpr
// CHECK-NEDT: `-DeclRefExpr {{.*}} 'x'
Bar a3{x};
// CHECK: `-VarDecl {{.*}} a4 'Bar'
// CHECK-NEXT: `-ParenListExpr {{.*}} 'NULL TYPE' contains-errors
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
Bar a4(invalid());
// CHECK: `-VarDecl {{.*}} a5 'Bar'
// CHECK-NEXT: `-InitListExpr {{.*}} contains-errors
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
Bar a5{invalid()};
// CHECK: `-VarDecl {{.*}} b1 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
Bar b1 = 1;
// CHECK: `-VarDecl {{.*}} b2 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-InitListExpr
Bar b2 = {1};
// CHECK: `-VarDecl {{.*}} b3 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'Bar' contains-errors
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int'
Bar b3 = Bar(x);
// CHECK: `-VarDecl {{.*}} b4 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'Bar' contains-errors
// CHECK-NEXT: `-InitListExpr {{.*}} 'void'
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int'
Bar b4 = Bar{x};
// CHECK: `-VarDecl {{.*}} b5 'Bar'
// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar'
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
Bar b5 = Bar(invalid());
// CHECK: `-VarDecl {{.*}} b6 'Bar'
// CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar'
// CHECK-NEXT: `-InitListExpr {{.*}} contains-errors
// CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
Bar b6 = Bar{invalid()};
// CHECK: RecoveryExpr {{.*}} 'Bar' contains-errors
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
Bar(1);
// CHECK: `-VarDecl {{.*}} var1
// CHECK-NEXT: `-BinaryOperator {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
int var1 = undef + 1;
}
void InitializerForAuto() {
// CHECK: `-VarDecl {{.*}} invalid a 'auto'
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
auto a = invalid();
// CHECK: `-VarDecl {{.*}} invalid b 'auto'
// CHECK-NEXT: `-CallExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func'
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid'
auto b = some_func(invalid());
decltype(ned);
// very bad initailizer: there is an unresolved typo expr internally, we just
// drop it.
// CHECK: `-VarDecl {{.*}} invalid unresolved_typo 'auto'
auto unresolved_typo = gned.*[] {};
}
// Verified that the generated call operator is invalid.
// CHECK: |-CXXMethodDecl {{.*}} invalid operator() 'auto () const -> auto'
using Escape = decltype([] { return undef(); }());
// CHECK: VarDecl {{.*}} NoCrashOnInvalidInitList
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors lvalue
// CHECK-NEXT: `-InitListExpr
// CHECK-NEXT: `-DesignatedInitExpr {{.*}} 'void'
// CHECK-NEXT: `-CXXNullPtrLiteralExpr {{.*}} 'std::nullptr_t'
struct {
int& abc;
} NoCrashOnInvalidInitList = {
.abc = nullptr,
};
// Verify the value category of recovery expression.
int prvalue(int);
int &lvalue(int);
int &&xvalue(int);
void ValueCategory() {
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors
prvalue(); // call to a function (nonreference return type) yields a prvalue (not print by default)
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors lvalue
lvalue(); // call to a function (lvalue reference return type) yields an lvalue.
// CHECK: RecoveryExpr {{.*}} 'int' contains-errors xvalue
xvalue(); // call to a function (rvalue reference return type) yields an xvalue.
}
void InvalidCondition() {
// CHECK: IfStmt {{.*}}
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:7, col:15> '<dependent type>' contains-errors
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} <col:7>
if (invalid()) {}
// CHECK: WhileStmt {{.*}}
// CHECK-NEXT: |-RecoveryExpr {{.*}} <col:10, col:18> '<dependent type>' contains-errors
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} <col:10>
while (invalid()) {}
// CHECK: SwitchStmt {{.*}}
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} <col:10>
switch(invalid()) {
case 1:
break;
}
// FIXME: figure out why the type of ConditionalOperator is not int.
// CHECK: ConditionalOperator {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}}
// CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2
invalid() ? 1 : 2;
}
void CtorInitializer() {
struct S{int m};
class MemberInit {
int x, y, z;
S s;
MemberInit() : x(invalid), y(invalid, invalid), z(invalid()), s(1,2) {}
// CHECK: CXXConstructorDecl {{.*}} MemberInit 'void ()'
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'x' 'int'
// CHECK-NEXT: | `-ParenListExpr
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'y' 'int'
// CHECK-NEXT: | `-ParenListExpr
// CHECK-NEXT: | |-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 'z' 'int'
// CHECK-NEXT: | `-ParenListExpr
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: | `-UnresolvedLookupExpr {{.*}} '<overloaded function type>'
// CHECK-NEXT: |-CXXCtorInitializer Field {{.*}} 's' 'S'
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'S' contains-errors
// CHECK-NEXT: | |-IntegerLiteral {{.*}} 1
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 2
};
class BaseInit : S {
BaseInit(float) : S("no match") {}
// CHECK: CXXConstructorDecl {{.*}} BaseInit 'void (float)'
// CHECK-NEXT: |-ParmVarDecl
// CHECK-NEXT: |-CXXCtorInitializer 'S'
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'S'
// CHECK-NEXT: | `-StringLiteral
BaseInit(double) : S(invalid) {}
// CHECK: CXXConstructorDecl {{.*}} BaseInit 'void (double)'
// CHECK-NEXT: |-ParmVarDecl
// CHECK-NEXT: |-CXXCtorInitializer 'S'
// CHECK-NEXT: | `-ParenListExpr
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
};
class DelegatingInit {
DelegatingInit(float) : DelegatingInit("no match") {}
// CHECK: CXXConstructorDecl {{.*}} DelegatingInit 'void (float)'
// CHECK-NEXT: |-ParmVarDecl
// CHECK-NEXT: |-CXXCtorInitializer 'DelegatingInit'
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'DelegatingInit'
// CHECK-NEXT: | `-StringLiteral
DelegatingInit(double) : DelegatingInit(invalid) {}
// CHECK: CXXConstructorDecl {{.*}} DelegatingInit 'void (double)'
// CHECK-NEXT: |-ParmVarDecl
// CHECK-NEXT: |-CXXCtorInitializer 'DelegatingInit'
// CHECK-NEXT: | `-ParenListExpr
// CHECK-NEXT: | `-RecoveryExpr {{.*}} '<dependent type>'
};
}
float *brokenReturn() {
// CHECK: FunctionDecl {{.*}} brokenReturn
return 42;
// CHECK: ReturnStmt
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'float *'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 42
}
// Return deduction treats the first, second *and* third differently!
auto *brokenDeducedReturn(int *x, float *y, double *z) {
// CHECK: FunctionDecl {{.*}} invalid brokenDeducedReturn
if (x) return x;
// CHECK: ReturnStmt
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <LValueToRValue>
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int *'
if (y) return y;
// CHECK: ReturnStmt
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int *'
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'y' 'float *'
if (z) return z;
// CHECK: ReturnStmt
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int *'
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'z' 'double *'
return x;
// Unfortunate: we wrap a valid return in RecoveryExpr.
// This is to avoid running deduction again after it failed once.
// CHECK: ReturnStmt
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int *'
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' 'int *'
}
void returnInitListFromVoid() {
// CHECK: FunctionDecl {{.*}} returnInitListFromVoid
return {7,8};
// CHECK: ReturnStmt
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 7
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 8
}
void RecoveryExprForInvalidDecls(Unknown InvalidDecl) {
InvalidDecl + 1;
// CHECK: BinaryOperator {{.*}}
// CHECK-NEXT: |-RecoveryExpr {{.*}} '<dependent type>'
// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'InvalidDecl' 'int'
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
InvalidDecl();
// CHECK: CallExpr {{.*}}
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
}
void InitializerOfInvalidDecl() {
int ValidDecl;
Unkown InvalidDecl = ValidDecl;
// CHECK: VarDecl {{.*}} invalid InvalidDecl
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'ValidDecl'
Unknown InvalidDeclWithInvalidInit = Invalid;
// CHECK: VarDecl {{.*}} invalid InvalidDeclWithInvalidInit
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
// CHECK-NOT: `-TypoExpr
}
void RecoverToAnInvalidDecl() {
Unknown* foo; // invalid decl
goo; // the typo was correct to the invalid foo.
// Verify that RecoveryExpr has an inner DeclRefExpr.
// CHECK: RecoveryExpr {{.*}} '<dependent type>' contains-errors lvalue
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
}
void RecoveryToDoWhileStmtCond() {
// CHECK: FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
// CHECK: `-DoStmt {{.*}}
// CHECK-NEXT: |-CompoundStmt {{.*}}
// CHECK-NEXT: `-BinaryOperator {{.*}} '<dependent type>' contains-errors '<'
// CHECK-NEXT: |-BinaryOperator {{.*}} '<dependent type>' contains-errors '+'
// CHECK-NEXT: | |-RecoveryExpr {{.*}} '<dependent type>' contains-errors lvalue
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 10
do {} while (some_invalid_val + 1 < 10);
}
void RecoveryForStmtCond() {
// CHECK:FunctionDecl {{.*}} RecoveryForStmtCond
// CHECK-NEXT:`-CompoundStmt {{.*}}
// CHECK-NEXT: `-ForStmt {{.*}}
// CHECK-NEXT: |-DeclStmt {{.*}}
// CHECK-NEXT: | `-VarDecl {{.*}}
// CHECK-NEXT: | `-IntegerLiteral {{.*}} <col:16> 'int' 0
// CHECK-NEXT: |-<<<NULL>>>
// CHECK-NEXT: |-RecoveryExpr {{.*}} 'bool' contains-errors
// CHECK-NEXT: |-UnaryOperator {{.*}} 'int' lvalue prefix '++'
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'i' 'int'
// CHECK-NEXT: `-CompoundStmt {{.*}}
for (int i = 0; i < invalid; ++i) {}
}