Skip to content

Commit d8236b6

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

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
@@ -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: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13435,16 +13435,18 @@ 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)) {
13444-
// Pure-specifiers are handled in ActOnPureSpecifier.
13445-
Diag(Method->getLocation(), diag::err_member_function_initialization)
13446-
<< Method->getDeclName() << Init->getSourceRange();
13447-
Method->setInvalidDecl();
13443+
if (auto *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
13444+
if (!Method->isInvalidDecl()) {
13445+
// Pure-specifiers are handled in ActOnPureSpecifier.
13446+
Diag(Method->getLocation(), diag::err_member_function_initialization)
13447+
<< Method->getDeclName() << Init->getSourceRange();
13448+
Method->setInvalidDecl();
13449+
}
1344813450
return;
1344913451
}
1345013452

@@ -13456,6 +13458,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1345613458
return;
1345713459
}
1345813460

13461+
if (VDecl->isInvalidDecl()) {
13462+
CorrectDelayedTyposInExpr(Init, VDecl);
13463+
ExprResult Recovery =
13464+
CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), {Init});
13465+
if (Expr *E = Recovery.get())
13466+
VDecl->setInit(E);
13467+
return;
13468+
}
13469+
1345913470
// WebAssembly tables can't be used to initialise a variable.
1346013471
if (Init && !Init->getType().isNull() &&
1346113472
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)