Skip to content

Commit c24e79d

Browse files
[clang][Sema] Preserve the initializer of invalid VarDecls
Fixes clangd/clangd#1821
1 parent 9617da8 commit c24e79d

File tree

3 files changed

+23
-4
lines changed

3 files changed

+23
-4
lines changed

clang/lib/Sema/JumpDiagnostics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) {
179179
}
180180

181181
const Expr *Init = VD->getInit();
182-
if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init) {
182+
if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init &&
183+
!Init->containsErrors()) {
183184
// C++11 [stmt.dcl]p3:
184185
// A program that jumps from a point where a variable with automatic
185186
// storage duration is not in scope to a point where it is in scope

clang/lib/Sema/SemaDecl.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13435,15 +13435,16 @@ void Sema::checkNonTrivialCUnion(QualType QT, SourceLocation Loc,
1343513435
void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1343613436
// If there is no declaration, there was an error parsing it. Just ignore
1343713437
// the initializer.
13438-
if (!RealDecl || RealDecl->isInvalidDecl()) {
13438+
if (!RealDecl) {
1343913439
CorrectDelayedTyposInExpr(Init, dyn_cast_or_null<VarDecl>(RealDecl));
1344013440
return;
1344113441
}
1344213442

13443-
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
13443+
if (auto *Method = dyn_cast<CXXMethodDecl>(RealDecl);
13444+
Method && !Method->isInvalidDecl()) {
1344413445
// Pure-specifiers are handled in ActOnPureSpecifier.
1344513446
Diag(Method->getLocation(), diag::err_member_function_initialization)
13446-
<< Method->getDeclName() << Init->getSourceRange();
13447+
<< Method->getDeclName() << Init->getSourceRange();
1344713448
Method->setInvalidDecl();
1344813449
return;
1344913450
}
@@ -13456,6 +13457,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1345613457
return;
1345713458
}
1345813459

13460+
if (VDecl->isInvalidDecl()) {
13461+
CorrectDelayedTyposInExpr(Init, VDecl);
13462+
ExprResult Recovery =
13463+
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), {Init});
13464+
if (Expr *E = Recovery.get())
13465+
VDecl->setInit(E);
13466+
return;
13467+
}
13468+
1345913469
// WebAssembly tables can't be used to initialise a variable.
1346013470
if (Init && !Init->getType().isNull() &&
1346113471
Init->getType()->isWebAssemblyTableType()) {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,14 @@ void RecoveryExprForInvalidDecls(Unknown InvalidDecl) {
413413
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
414414
}
415415

416+
void InitializerOfInvalidDecl() {
417+
int ValidDecl;
418+
Unkown InvalidDecl = ValidDecl;
419+
// CHECK: VarDecl {{.*}} invalid InvalidDecl
420+
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>' contains-errors
421+
// CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'ValidDecl'
422+
}
423+
416424
void RecoverToAnInvalidDecl() {
417425
Unknown* foo; // invalid decl
418426
goo; // the typo was correct to the invalid foo.

0 commit comments

Comments
 (0)