diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -388,7 +388,26 @@ void test(S2 s2) { s2[[-^>]]f(); } - )cpp", "DeclRefExpr"} // DeclRefExpr to the "operator->" method. + )cpp", + "DeclRefExpr"}, // DeclRefExpr to the "operator->" method. + + // broken cases, missing } brace. + { + R"cpp( + // error-ok: AST is still valid on missing } brace. + class ABC { + [[int ^a]]; + // } + )cpp", + "FieldDecl"}, + { + R"cpp( + // error-ok + enum Color { + [[^Black]], + //} + )cpp", + "EnumConstantDecl"}, }; for (const Case &C : Cases) { trace::TestTracer Tracer; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -4126,8 +4126,8 @@ } SourceRange TagDecl::getSourceRange() const { - SourceLocation RBraceLoc = BraceRange.getEnd(); - SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation(); + SourceLocation E = BraceRange.getBegin().isValid() ? + BraceRange.getEnd() : getLocation(); return SourceRange(getOuterLocStart(), E); } diff --git a/clang/test/AST/ast-dump-invalid-brace.cpp b/clang/test/AST/ast-dump-invalid-brace.cpp new file mode 100644 --- /dev/null +++ b/clang/test/AST/ast-dump-invalid-brace.cpp @@ -0,0 +1,6 @@ +// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s + +// CHECK: CXXRecordDecl {{.*}}:4:1, +class Test { + int abc; +// }