Skip to content

Commit

Permalink
[AST] Use RecoveryExpr to model a DeclRefExpr which refers to an inva…
Browse files Browse the repository at this point in the history
…lid Decl.

Previously, we didin't build a DeclRefExpr which refers to an invalid declaration.

In this patch, we handle this case by building an empty RecoveryExpr,
which will preserve more broken code (AST parent nodes that contain the
RecoveryExpr is preserved in the AST).

Differential Revision: https://reviews.llvm.org/D120812
  • Loading branch information
hokein committed Mar 3, 2022
1 parent c262ba2 commit ba6c71b
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 4 deletions.
8 changes: 6 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Expand Up @@ -3228,8 +3228,12 @@ ExprResult Sema::BuildDeclarationNameExpr(
"Cannot refer unambiguously to a function template");

SourceLocation Loc = NameInfo.getLoc();
if (CheckDeclInExpr(*this, Loc, D))
return ExprError();
if (CheckDeclInExpr(*this, Loc, D)) {
// Recovery from invalid cases (e.g. D is an invalid Decl).
// We use the dependent type for the RecoveryExpr to prevent bogus follow-up
// diagnostics, as invalid decls use int as a fallback type.
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
}

if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
// Specifically diagnose references to class templates that are missing
Expand Down
10 changes: 10 additions & 0 deletions clang/test/AST/ast-dump-recovery.cpp
Expand Up @@ -401,3 +401,13 @@ void returnInitListFromVoid() {
// 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: `-IntegerLiteral {{.*}} 'int' 1
InvalidDecl();
// CHECK: CallExpr {{.*}}
// CHECK-NEXT: `-RecoveryExpr {{.*}} '<dependent type>'
}
1 change: 0 additions & 1 deletion clang/test/Sema/ms-inline-asm.c
Expand Up @@ -78,7 +78,6 @@ void t3(void) {
__asm { mov eax, [eax] UndeclaredId } // expected-error {{unknown token in expression}} expected-error {{use of undeclared label 'UndeclaredId'}}

// FIXME: Only emit one diagnostic here.
// expected-error@+3 {{use of undeclared label 'A'}}
// expected-error@+2 {{unexpected type name 'A': expected expression}}
// expected-error@+1 {{unknown token in expression}}
__asm { mov eax, [eax] A }
Expand Down
4 changes: 3 additions & 1 deletion clang/test/SemaCXX/constructor-initializer.cpp
Expand Up @@ -249,7 +249,9 @@ namespace test3 {
class B : public A {
public:
B(const String& s, int e=0) // expected-error {{unknown type name}}
: A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} expected-error {{does not name}}
: A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} \
expected-error {{member initializer 'm_String' does not name}} \
expected-error {{member initializer 'm_ErrorStr' does not name}}
B(const B& e)
: A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error 2{{does not name}} \
// expected-error {{no member named 'm_String' in 'test3::B'}}
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/copy-assignment.cpp
Expand Up @@ -114,6 +114,7 @@ void test() {
namespace test1 {
template<typename T> class A : public unknown::X { // expected-error {{undeclared identifier 'unknown'}} expected-error {{expected class name}}
A(UndeclaredType n) : X(n) {} // expected-error {{unknown type name 'UndeclaredType'}}
// expected-error@-1 {{member initializer 'X' does not name a non-static data member or base class}}
};
template<typename T> class B : public A<T> {
virtual void foo() {}
Expand Down

0 comments on commit ba6c71b

Please sign in to comment.