Skip to content

Commit d530894

Browse files
[clang][Sema] Preserve the initializer of invalid VarDecls (#88645)
Fixes clangd/clangd#1821
1 parent b9f2c16 commit d530894

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

clang/lib/Sema/JumpDiagnostics.cpp

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

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

clang/lib/Sema/SemaDecl.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13502,16 +13502,18 @@ void Sema::checkNonTrivialCUnion(QualType QT, SourceLocation Loc,
1350213502
void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1350313503
// If there is no declaration, there was an error parsing it. Just ignore
1350413504
// the initializer.
13505-
if (!RealDecl || RealDecl->isInvalidDecl()) {
13505+
if (!RealDecl) {
1350613506
CorrectDelayedTyposInExpr(Init, dyn_cast_or_null<VarDecl>(RealDecl));
1350713507
return;
1350813508
}
1350913509

13510-
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
13511-
// Pure-specifiers are handled in ActOnPureSpecifier.
13512-
Diag(Method->getLocation(), diag::err_member_function_initialization)
13513-
<< Method->getDeclName() << Init->getSourceRange();
13514-
Method->setInvalidDecl();
13510+
if (auto *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
13511+
if (!Method->isInvalidDecl()) {
13512+
// Pure-specifiers are handled in ActOnPureSpecifier.
13513+
Diag(Method->getLocation(), diag::err_member_function_initialization)
13514+
<< Method->getDeclName() << Init->getSourceRange();
13515+
Method->setInvalidDecl();
13516+
}
1351513517
return;
1351613518
}
1351713519

@@ -13523,6 +13525,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1352313525
return;
1352413526
}
1352513527

13528+
if (VDecl->isInvalidDecl()) {
13529+
CorrectDelayedTyposInExpr(Init, VDecl);
13530+
ExprResult Recovery =
13531+
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), {Init});
13532+
if (Expr *E = Recovery.get())
13533+
VDecl->setInit(E);
13534+
return;
13535+
}
13536+
1352613537
// WebAssembly tables can't be used to initialise a variable.
1352713538
if (Init && !Init->getType().isNull() &&
1352813539
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)