Skip to content

Commit 68dc4b9

Browse files
committed
[Clang] adjust caret placement for the suggested attribute location for enum class
1 parent 2e489f7 commit 68dc4b9

File tree

3 files changed

+54
-20
lines changed

3 files changed

+54
-20
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ Improvements to Clang's diagnostics
420420
or continue (#GH166013)
421421
- Clang now emits a diagnostic in case `vector_size` or `ext_vector_type`
422422
attributes are used with a negative size (#GH165463).
423+
- Clang now provides correct caret placement when attributes appear before
424+
`enum class` (#GH163224).
423425

424426
Improvements to Clang's time-trace
425427
----------------------------------

clang/lib/Parse/Parser.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,30 +1100,32 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
11001100
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
11011101
// declaration-specifiers init-declarator-list[opt] ';'
11021102
if (Tok.is(tok::semi)) {
1103-
auto LengthOfTSTToken = [](DeclSpec::TST TKind) {
1104-
assert(DeclSpec::isDeclRep(TKind));
1105-
switch(TKind) {
1106-
case DeclSpec::TST_class:
1107-
return 5;
1108-
case DeclSpec::TST_struct:
1109-
return 6;
1110-
case DeclSpec::TST_union:
1111-
return 5;
1112-
case DeclSpec::TST_enum:
1113-
return 4;
1114-
case DeclSpec::TST_interface:
1115-
return 9;
1116-
default:
1117-
llvm_unreachable("we only expect to get the length of the class/struct/union/enum");
1103+
auto GetAdjustedAttrsLoc = [&]() {
1104+
auto TKind = DS.getTypeSpecType();
1105+
if (!DeclSpec::isDeclRep(TKind))
1106+
return SourceLocation();
1107+
1108+
if (TKind == DeclSpec::TST_enum) {
1109+
const auto *ED = dyn_cast_or_null<EnumDecl>(DS.getRepAsDecl());
1110+
if (ED && ED->isScoped()) {
1111+
const auto &SM = Actions.getSourceManager();
1112+
const auto &LangOpts = Actions.getLangOpts();
1113+
auto End = Lexer::getLocForEndOfToken(DS.getTypeSpecTypeLoc(),
1114+
/*Offset*/ 0, SM, LangOpts);
1115+
auto NextToken = Lexer::findNextToken(End, SM, LangOpts);
1116+
if (NextToken)
1117+
return NextToken->getEndLoc();
1118+
}
11181119
}
11191120

1121+
const auto &Policy = Actions.getASTContext().getPrintingPolicy();
1122+
unsigned Offset =
1123+
StringRef(DeclSpec::getSpecifierName(TKind, Policy)).size();
1124+
return DS.getTypeSpecTypeLoc().getLocWithOffset(Offset);
11201125
};
1126+
11211127
// Suggest correct location to fix '[[attrib]] struct' to 'struct [[attrib]]'
1122-
SourceLocation CorrectLocationForAttributes =
1123-
DeclSpec::isDeclRep(DS.getTypeSpecType())
1124-
? DS.getTypeSpecTypeLoc().getLocWithOffset(
1125-
LengthOfTSTToken(DS.getTypeSpecType()))
1126-
: SourceLocation();
1128+
SourceLocation CorrectLocationForAttributes = GetAdjustedAttrsLoc();
11271129
ProhibitAttributes(Attrs, CorrectLocationForAttributes);
11281130
ConsumeToken();
11291131
RecordDecl *AnonRecord = nullptr;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s -strict-whitespace
3+
4+
[[nodiscard]] enum class E1 { };
5+
// expected-error@-1 {{misplaced attributes; expected attributes here}}
6+
// CHECK: {{^}}{{\[\[}}nodiscard]] enum class E1 { };
7+
// CHECK: {{^}}~~~~~~~~~~~~~ ^
8+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
9+
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:25-[[@LINE-5]]:25}:"{{\[\[}}nodiscard]]"
10+
11+
[[nodiscard]] enum struct E2 { };
12+
// expected-error@-1 {{misplaced attributes; expected attributes here}}
13+
// CHECK: {{^}}{{\[\[}}nodiscard]] enum struct E2 { };
14+
// CHECK: {{^}}~~~~~~~~~~~~~ ^
15+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
16+
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:26-[[@LINE-5]]:26}:"{{\[\[}}nodiscard]]"
17+
18+
[[nodiscard]] enum class E3 { };
19+
// expected-error@-1 {{misplaced attributes; expected attributes here}}
20+
// CHECK: {{^}}{{\[\[}}nodiscard]] enum class E3 { };
21+
// CHECK: {{^}}~~~~~~~~~~~~~ ^
22+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
23+
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:34-[[@LINE-5]]:34}:"{{\[\[}}nodiscard]]"
24+
25+
[[nodiscard]] enum /*comment*/ class E4 { };
26+
// expected-error@-1 {{misplaced attributes; expected attributes here}}
27+
// CHECK: {{^}}{{\[\[}}nodiscard]] enum /*comment*/ class E4 { };
28+
// CHECK: {{^}}~~~~~~~~~~~~~ ^
29+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
30+
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:38-[[@LINE-5]]:38}:"{{\[\[}}nodiscard]]"

0 commit comments

Comments
 (0)