Skip to content

Commit 1b4800c

Browse files
committed
[clang][parser] Set source ranges for GNU-style attributes
Set the source ranges for parsed GNU-style attributes in ParseGNUAttributes(), the same way that ParseCXX11Attributes() does it. Differential Revision: https://reviews.llvm.org/D75844
1 parent 5207cde commit 1b4800c

File tree

7 files changed

+120
-42
lines changed

7 files changed

+120
-42
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,27 +1572,6 @@ class Parser : public CodeCompletionHandler {
15721572

15731573
//===--------------------------------------------------------------------===//
15741574
// C99 6.9: External Definitions.
1575-
struct ParsedAttributesWithRange : ParsedAttributes {
1576-
ParsedAttributesWithRange(AttributeFactory &factory)
1577-
: ParsedAttributes(factory) {}
1578-
1579-
void clear() {
1580-
ParsedAttributes::clear();
1581-
Range = SourceRange();
1582-
}
1583-
1584-
SourceRange Range;
1585-
};
1586-
struct ParsedAttributesViewWithRange : ParsedAttributesView {
1587-
ParsedAttributesViewWithRange() : ParsedAttributesView() {}
1588-
void clearListOnly() {
1589-
ParsedAttributesView::clearListOnly();
1590-
Range = SourceRange();
1591-
}
1592-
1593-
SourceRange Range;
1594-
};
1595-
15961575
DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
15971576
ParsingDeclSpec *DS = nullptr);
15981577
bool isDeclarationAfterDeclarator();
@@ -2725,17 +2704,50 @@ class Parser : public CodeCompletionHandler {
27252704
D.takeAttributes(attrs, endLoc);
27262705
}
27272706
}
2728-
bool MaybeParseGNUAttributes(ParsedAttributes &attrs,
2729-
SourceLocation *endLoc = nullptr,
2707+
2708+
/// Parses GNU-style attributes and returns them without source range
2709+
/// information.
2710+
///
2711+
/// This API is discouraged. Use the version that takes a
2712+
/// ParsedAttributesWithRange instead.
2713+
bool MaybeParseGNUAttributes(ParsedAttributes &Attrs,
2714+
SourceLocation *EndLoc = nullptr,
27302715
LateParsedAttrList *LateAttrs = nullptr) {
27312716
if (Tok.is(tok::kw___attribute)) {
2732-
ParseGNUAttributes(attrs, endLoc, LateAttrs);
2717+
ParsedAttributesWithRange AttrsWithRange(AttrFactory);
2718+
ParseGNUAttributes(Attrs, EndLoc, LateAttrs);
2719+
Attrs.takeAllFrom(AttrsWithRange);
27332720
return true;
27342721
}
27352722
return false;
27362723
}
2737-
void ParseGNUAttributes(ParsedAttributes &attrs,
2738-
SourceLocation *endLoc = nullptr,
2724+
2725+
bool MaybeParseGNUAttributes(ParsedAttributesWithRange &Attrs,
2726+
SourceLocation *EndLoc = nullptr,
2727+
LateParsedAttrList *LateAttrs = nullptr) {
2728+
if (Tok.is(tok::kw___attribute)) {
2729+
ParseGNUAttributes(Attrs, EndLoc, LateAttrs);
2730+
return true;
2731+
}
2732+
return false;
2733+
}
2734+
2735+
/// Parses GNU-style attributes and returns them without source range
2736+
/// information.
2737+
///
2738+
/// This API is discouraged. Use the version that takes a
2739+
/// ParsedAttributesWithRange instead.
2740+
void ParseGNUAttributes(ParsedAttributes &Attrs,
2741+
SourceLocation *EndLoc = nullptr,
2742+
LateParsedAttrList *LateAttrs = nullptr,
2743+
Declarator *D = nullptr) {
2744+
ParsedAttributesWithRange AttrsWithRange(AttrFactory);
2745+
ParseGNUAttributes(AttrsWithRange, EndLoc, LateAttrs, D);
2746+
Attrs.takeAllFrom(AttrsWithRange);
2747+
}
2748+
2749+
void ParseGNUAttributes(ParsedAttributesWithRange &Attrs,
2750+
SourceLocation *EndLoc = nullptr,
27392751
LateParsedAttrList *LateAttrs = nullptr,
27402752
Declarator *D = nullptr);
27412753
void ParseGNUAttributeArgs(IdentifierInfo *AttrName,

clang/include/clang/Sema/ParsedAttr.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,27 @@ class ParsedAttributes : public ParsedAttributesView {
10481048
mutable AttributePool pool;
10491049
};
10501050

1051+
struct ParsedAttributesWithRange : ParsedAttributes {
1052+
ParsedAttributesWithRange(AttributeFactory &factory)
1053+
: ParsedAttributes(factory) {}
1054+
1055+
void clear() {
1056+
ParsedAttributes::clear();
1057+
Range = SourceRange();
1058+
}
1059+
1060+
SourceRange Range;
1061+
};
1062+
struct ParsedAttributesViewWithRange : ParsedAttributesView {
1063+
ParsedAttributesViewWithRange() : ParsedAttributesView() {}
1064+
void clearListOnly() {
1065+
ParsedAttributesView::clearListOnly();
1066+
Range = SourceRange();
1067+
}
1068+
1069+
SourceRange Range;
1070+
};
1071+
10511072
/// These constants match the enumerated choices of
10521073
/// err_attribute_argument_n_type and err_attribute_argument_type.
10531074
enum AttributeArgumentNType {

clang/lib/Parse/ParseDecl.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,19 @@ void Parser::ParseAttributes(unsigned WhichAttrKinds,
162162
/// ',' or ')' are ignored, otherwise they produce a parse error.
163163
///
164164
/// We follow the C++ model, but don't allow junk after the identifier.
165-
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
166-
SourceLocation *endLoc,
167-
LateParsedAttrList *LateAttrs,
168-
Declarator *D) {
165+
void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs,
166+
SourceLocation *EndLoc,
167+
LateParsedAttrList *LateAttrs, Declarator *D) {
169168
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
170169

170+
SourceLocation StartLoc = Tok.getLocation(), Loc;
171+
172+
if (!EndLoc)
173+
EndLoc = &Loc;
174+
171175
while (Tok.is(tok::kw___attribute)) {
172176
SourceLocation AttrTokLoc = ConsumeToken();
173-
unsigned OldNumAttrs = attrs.size();
177+
unsigned OldNumAttrs = Attrs.size();
174178
unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0;
175179

176180
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
@@ -198,14 +202,14 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
198202
SourceLocation AttrNameLoc = ConsumeToken();
199203

200204
if (Tok.isNot(tok::l_paren)) {
201-
attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
205+
Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
202206
ParsedAttr::AS_GNU);
203207
continue;
204208
}
205209

206210
// Handle "parameterized" attributes
207211
if (!LateAttrs || !isAttributeLateParsed(*AttrName)) {
208-
ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr,
212+
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, nullptr,
209213
SourceLocation(), ParsedAttr::AS_GNU, D);
210214
continue;
211215
}
@@ -238,8 +242,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
238242
SourceLocation Loc = Tok.getLocation();
239243
if (ExpectAndConsume(tok::r_paren))
240244
SkipUntil(tok::r_paren, StopAtSemi);
241-
if (endLoc)
242-
*endLoc = Loc;
245+
if (EndLoc)
246+
*EndLoc = Loc;
243247

244248
// If this was declared in a macro, attach the macro IdentifierInfo to the
245249
// parsed attribute.
@@ -251,15 +255,17 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
251255
Lexer::getSourceText(ExpansionRange, SM, PP.getLangOpts());
252256
IdentifierInfo *MacroII = PP.getIdentifierInfo(FoundName);
253257

254-
for (unsigned i = OldNumAttrs; i < attrs.size(); ++i)
255-
attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());
258+
for (unsigned i = OldNumAttrs; i < Attrs.size(); ++i)
259+
Attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());
256260

257261
if (LateAttrs) {
258262
for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i)
259263
(*LateAttrs)[i]->MacroII = MacroII;
260264
}
261265
}
262266
}
267+
268+
Attrs.Range = SourceRange(StartLoc, *EndLoc);
263269
}
264270

265271
/// Determine whether the given attribute has an identifier argument.

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
18521852
} else if (TUK == Sema::TUK_Reference ||
18531853
(TUK == Sema::TUK_Friend &&
18541854
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
1855-
ProhibitAttributes(attrs);
1855+
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
1856+
/*DiagnoseEmptyAttrs=*/true);
18561857
TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
18571858
SS,
18581859
TemplateId->TemplateKWLoc,
@@ -1924,7 +1925,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
19241925
TagType, StartLoc, SS, Name, NameLoc, attrs);
19251926
} else if (TUK == Sema::TUK_Friend &&
19261927
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
1927-
ProhibitAttributes(attrs);
1928+
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
1929+
/*DiagnoseEmptyAttrs=*/true);
19281930

19291931
TagOrTempResult = Actions.ActOnTemplatedFriendTag(
19301932
getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name,

clang/test/AST/sourceranges.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,24 @@ namespace attributed_decl {
108108
}
109109
}
110110

111+
// CHECK-1Z: NamespaceDecl {{.*}} attributed_case
112+
namespace attributed_case {
113+
void f(int n) {
114+
switch (n) {
115+
case 0:
116+
n--;
117+
// CHECK: AttributedStmt {{.*}} <line:[[@LINE+2]]:5, line:[[@LINE+4]]:35>
118+
// CHECK: FallThroughAttr {{.*}} <line:[[@LINE+1]]:20>
119+
__attribute__((fallthrough))
120+
// CHECK: FallThroughAttr {{.*}} <line:[[@LINE+1]]:22>
121+
__attribute__((fallthrough));
122+
case 1:
123+
n++;
124+
break;
125+
}
126+
}
127+
} // namespace attributed_case
128+
111129
// CHECK: NamespaceDecl {{.*}} attributed_stmt
112130
namespace attributed_stmt {
113131
// In DO_PRAGMA and _Pragma cases, `LoopHintAttr` comes from <scratch space>

clang/test/Parser/cxx0x-attributes.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions %s
1+
// RUN: %clang_cc1 -fcxx-exceptions -fdeclspec -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions %s
22

33
// Need std::initializer_list
44
namespace std {
@@ -368,6 +368,22 @@ int fallthru(int n) {
368368
return n;
369369
}
370370

371+
template<typename T> struct TemplateStruct {};
372+
class FriendClassesWithAttributes {
373+
// We allow GNU-style attributes here
374+
template <class _Tp, class _Alloc> friend class __attribute__((__type_visibility__("default"))) vector;
375+
template <class _Tp, class _Alloc> friend class __declspec(code_seg("whatever")) vector2;
376+
// But not C++11 ones
377+
template <class _Tp, class _Alloc> friend class[[]] vector3; // expected-error {{an attribute list cannot appear here}}
378+
template <class _Tp, class _Alloc> friend class [[clang::__type_visibility__(("default"))]] vector4; // expected-error {{an attribute list cannot appear here}}
379+
380+
// Also allowed
381+
friend struct __attribute__((__type_visibility__("default"))) TemplateStruct<FriendClassesWithAttributes>;
382+
friend struct __declspec(code_seg("whatever")) TemplateStruct<FriendClassesWithAttributes>;
383+
friend struct[[]] TemplateStruct<FriendClassesWithAttributes>; // expected-error {{an attribute list cannot appear here}}
384+
friend struct [[clang::__type_visibility__("default")]] TemplateStruct<FriendClassesWithAttributes>; // expected-error {{an attribute list cannot appear here}}
385+
};
386+
371387
#define attr_name bitand
372388
#define attr_name_2(x) x
373389
#define attr_name_3(x, y) x##y

clang/test/SemaCXX/switch-implicit-fallthrough.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,12 @@ int fallthrough_position(int n) {
185185
return 1;
186186
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
187187
case 222:
188+
return 2;
189+
__attribute__((fallthrough)); // expected-warning{{fallthrough annotation in unreachable code}}
190+
case 223:
188191
n += 400;
189-
case 223: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
190-
;
192+
case 224: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
193+
;
191194
}
192195

193196
long p = static_cast<long>(n) * n;

0 commit comments

Comments
 (0)