Skip to content

Commit

Permalink
[clang][parser] Set source ranges for GNU-style attributes
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tbaederr committed Apr 1, 2021
1 parent 7b921a6 commit 1ea9fa8
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 39 deletions.
64 changes: 38 additions & 26 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1572,27 +1572,6 @@ class Parser : public CodeCompletionHandler {

//===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
struct ParsedAttributesWithRange : ParsedAttributes {
ParsedAttributesWithRange(AttributeFactory &factory)
: ParsedAttributes(factory) {}

void clear() {
ParsedAttributes::clear();
Range = SourceRange();
}

SourceRange Range;
};
struct ParsedAttributesViewWithRange : ParsedAttributesView {
ParsedAttributesViewWithRange() : ParsedAttributesView() {}
void clearListOnly() {
ParsedAttributesView::clearListOnly();
Range = SourceRange();
}

SourceRange Range;
};

DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS = nullptr);
bool isDeclarationAfterDeclarator();
Expand Down Expand Up @@ -2725,17 +2704,50 @@ class Parser : public CodeCompletionHandler {
D.takeAttributes(attrs, endLoc);
}
}
bool MaybeParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = nullptr,

/// Parses GNU-style attributes and returns them without source range
/// information.
///
/// This API is discouraged. Use the version that takes a
/// ParsedAttributesWithRange instead.
bool MaybeParseGNUAttributes(ParsedAttributes &Attrs,
SourceLocation *EndLoc = nullptr,
LateParsedAttrList *LateAttrs = nullptr) {
if (Tok.is(tok::kw___attribute)) {
ParseGNUAttributes(attrs, endLoc, LateAttrs);
ParsedAttributesWithRange AttrsWithRange(AttrFactory);
ParseGNUAttributes(Attrs, EndLoc, LateAttrs);
Attrs.takeAllFrom(AttrsWithRange);
return true;
}
return false;
}
void ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = nullptr,

bool MaybeParseGNUAttributes(ParsedAttributesWithRange &Attrs,
SourceLocation *EndLoc = nullptr,
LateParsedAttrList *LateAttrs = nullptr) {
if (Tok.is(tok::kw___attribute)) {
ParseGNUAttributes(Attrs, EndLoc, LateAttrs);
return true;
}
return false;
}

/// Parses GNU-style attributes and returns them without source range
/// information.
///
/// This API is discouraged. Use the version that takes a
/// ParsedAttributesWithRange instead.
void ParseGNUAttributes(ParsedAttributes &Attrs,
SourceLocation *EndLoc = nullptr,
LateParsedAttrList *LateAttrs = nullptr,
Declarator *D = nullptr) {
ParsedAttributesWithRange AttrsWithRange(AttrFactory);
ParseGNUAttributes(AttrsWithRange, EndLoc, LateAttrs, D);
Attrs.takeAllFrom(AttrsWithRange);
}

void ParseGNUAttributes(ParsedAttributesWithRange &Attrs,
SourceLocation *EndLoc = nullptr,
LateParsedAttrList *LateAttrs = nullptr,
Declarator *D = nullptr);
void ParseGNUAttributeArgs(IdentifierInfo *AttrName,
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/Sema/ParsedAttr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,27 @@ class ParsedAttributes : public ParsedAttributesView {
mutable AttributePool pool;
};

struct ParsedAttributesWithRange : ParsedAttributes {
ParsedAttributesWithRange(AttributeFactory &factory)
: ParsedAttributes(factory) {}

void clear() {
ParsedAttributes::clear();
Range = SourceRange();
}

SourceRange Range;
};
struct ParsedAttributesViewWithRange : ParsedAttributesView {
ParsedAttributesViewWithRange() : ParsedAttributesView() {}
void clearListOnly() {
ParsedAttributesView::clearListOnly();
Range = SourceRange();
}

SourceRange Range;
};

/// These constants match the enumerated choices of
/// err_attribute_argument_n_type and err_attribute_argument_type.
enum AttributeArgumentNType {
Expand Down
28 changes: 17 additions & 11 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,19 @@ void Parser::ParseAttributes(unsigned WhichAttrKinds,
/// ',' or ')' are ignored, otherwise they produce a parse error.
///
/// We follow the C++ model, but don't allow junk after the identifier.
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc,
LateParsedAttrList *LateAttrs,
Declarator *D) {
void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs,
SourceLocation *EndLoc,
LateParsedAttrList *LateAttrs, Declarator *D) {
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");

SourceLocation StartLoc = Tok.getLocation(), Loc;

if (!EndLoc)
EndLoc = &Loc;

while (Tok.is(tok::kw___attribute)) {
SourceLocation AttrTokLoc = ConsumeToken();
unsigned OldNumAttrs = attrs.size();
unsigned OldNumAttrs = Attrs.size();
unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0;

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

if (Tok.isNot(tok::l_paren)) {
attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
ParsedAttr::AS_GNU);
continue;
}

// Handle "parameterized" attributes
if (!LateAttrs || !isAttributeLateParsed(*AttrName)) {
ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr,
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, nullptr,
SourceLocation(), ParsedAttr::AS_GNU, D);
continue;
}
Expand Down Expand Up @@ -238,8 +242,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation Loc = Tok.getLocation();
if (ExpectAndConsume(tok::r_paren))
SkipUntil(tok::r_paren, StopAtSemi);
if (endLoc)
*endLoc = Loc;
if (EndLoc)
*EndLoc = Loc;

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

for (unsigned i = OldNumAttrs; i < attrs.size(); ++i)
attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());
for (unsigned i = OldNumAttrs; i < Attrs.size(); ++i)
Attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());

if (LateAttrs) {
for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i)
(*LateAttrs)[i]->MacroII = MacroII;
}
}
}

Attrs.Range = SourceRange(StartLoc, *EndLoc);
}

/// Determine whether the given attribute has an identifier argument.
Expand Down
18 changes: 18 additions & 0 deletions clang/test/AST/sourceranges.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ namespace attributed_decl {
}
}

// CHECK-1Z: NamespaceDecl {{.*}} attributed_case
namespace attributed_case {
void f(int n) {
switch (n) {
case 0:
n--;
// CHECK: AttributedStmt {{.*}} <line:[[@LINE+2]]:5, line:[[@LINE+4]]:35>
// CHECK: FallThroughAttr {{.*}} <line:[[@LINE+1]]:20>
__attribute__((fallthrough))
// CHECK: FallThroughAttr {{.*}} <line:[[@LINE+1]]:22>
__attribute__((fallthrough));
case 1:
n++;
break;
}
}
} // namespace attributed_case

// CHECK: NamespaceDecl {{.*}} attributed_stmt
namespace attributed_stmt {
// In DO_PRAGMA and _Pragma cases, `LoopHintAttr` comes from <scratch space>
Expand Down
7 changes: 5 additions & 2 deletions clang/test/SemaCXX/switch-implicit-fallthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,12 @@ int fallthrough_position(int n) {
return 1;
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
case 222:
return 2;
__attribute__((fallthrough)); // expected-warning{{fallthrough annotation in unreachable code}}
case 223:
n += 400;
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}}
;
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}}
;
}

long p = static_cast<long>(n) * n;
Expand Down

0 comments on commit 1ea9fa8

Please sign in to comment.