[clang] Reject non-declaration C++11 attributes on declarations
For backwards compatiblity, we emit only a warning instead of an error if the attribute is one of the existing type attributes that we have historically allowed to "slide" to the `DeclSpec` just as if it had been specified in GNU syntax. (We will call these "legacy type attributes" below.) The high-level changes that achieve this are: - We introduce a new field `Declarator::DeclarationAttrs` (with appropriate accessors) to store C++11 attributes occurring in the attribute-specifier-seq at the beginning of a simple-declaration (and other similar declarations). Previously, these attributes were placed on the `DeclSpec`, which made it impossible to reconstruct later on whether the attributes had in fact been placed on the decl-specifier-seq or ahead of the declaration. - In the parser, we propgate declaration attributes and decl-specifier-seq attributes separately until we can place them in `Declarator::DeclarationAttrs` or `DeclSpec::Attrs`, respectively. - In `ProcessDeclAttributes()`, in addition to processing declarator attributes, we now also process the attributes from `Declarator::DeclarationAttrs` (except if they are legacy type attributes). - In `ConvertDeclSpecToType()`, in addition to processing `DeclSpec` attributes, we also process any legacy type attributes that occur in `Declarator::DeclarationAttrs` (and emit a warning). - We make `ProcessDeclAttribute` emit an error if it sees any non-declaration attributes in C++11 syntax, except in the following cases: - If it is being called for attributes on a `DeclSpec` or `DeclaratorChunk` - If the attribute is a legacy type attribute (in which case we only emit a warning) The standard justifies treating attributes at the beginning of a simple-declaration and attributes after a declarator-id the same. Here are some relevant parts of the standard: - The attribute-specifier-seq at the beginning of a simple-declaration "appertains to each of the entities declared by the declarators of the init-declarator-list" (https://eel.is/c++draft/dcl.dcl#dcl.pre-3) - "In the declaration for an entity, attributes appertaining to that entity can appear at the start of the declaration and after the declarator-id for that declaration." (https://eel.is/c++draft/dcl.dcl#dcl.pre-note-2) - "The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared." (https://eel.is/c++draft/dcl.dcl#dcl.meaning.general-1) The standard contains similar wording to that for a simple-declaration in other similar types of declarations, for example: - "The optional attribute-specifier-seq in a parameter-declaration appertains to the parameter." (https://eel.is/c++draft/dcl.fct#3) - "The optional attribute-specifier-seq in an exception-declaration appertains to the parameter of the catch clause" (https://eel.is/c++draft/except.pre#1) The new behavior is tested both on the newly added type attribute `annotate_type`, for which we emit errors, and for the legacy type attribute `address_space` (chosen somewhat randomly from the various legacy type attributes), for which we emit warnings. Depends On D111548 Reviewed By: aaron.ballman, rsmith Differential Revision: https://reviews.llvm.org/D126061
This commit is contained in:
parent
7acc88be03
commit
8c7b64b5ae
|
@ -150,6 +150,21 @@ public:
|
|||
|
||||
bool isAlignasAttribute() const {
|
||||
// FIXME: Use a better mechanism to determine this.
|
||||
// We use this in `isCXX11Attribute` below, so it _should_ only return
|
||||
// true for the `alignas` spelling, but it currently also returns true
|
||||
// for the `_Alignas` spelling, which only exists in C11. Distinguishing
|
||||
// between the two is important because they behave differently:
|
||||
// - `alignas` may only appear in the attribute-specifier-seq before
|
||||
// the decl-specifier-seq and is therefore associated with the
|
||||
// declaration.
|
||||
// - `_Alignas` may appear anywhere within the declaration-specifiers
|
||||
// and is therefore associated with the `DeclSpec`.
|
||||
// It's not clear how best to fix this:
|
||||
// - We have the necessary information in the form of the `SpellingIndex`,
|
||||
// but we would need to compare against AlignedAttr::Keyword_alignas,
|
||||
// and we can't depend on clang/AST/Attr.h here.
|
||||
// - We could test `getAttrName()->getName() == "alignas"`, but this is
|
||||
// inefficient.
|
||||
return getParsedKind() == AT_Aligned && isKeywordAttribute();
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,8 @@ def err_opencl_unknown_type_specifier : Error<
|
|||
|
||||
def warn_unknown_attribute_ignored : Warning<
|
||||
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
|
||||
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_use_of_tag_name_without_tag : Error<
|
||||
"must use '%1' tag to refer to type %0%select{| in this scope}2">;
|
||||
|
||||
|
|
|
@ -3354,8 +3354,6 @@ def warn_redeclaration_without_import_attribute : Warning<
|
|||
def warn_dllimport_dropped_from_inline_function : Warning<
|
||||
"%q0 redeclared inline; %1 attribute ignored">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_nothrow_attribute_ignored : Warning<"'nothrow' attribute conflicts with"
|
||||
" exception specification; attribute ignored">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
|
@ -3392,8 +3390,11 @@ def note_attribute_has_no_effect_on_compile_time_if_here : Note<
|
|||
"annotating the 'if %select{constexpr|consteval}0' statement here">;
|
||||
def err_decl_attribute_invalid_on_stmt : Error<
|
||||
"%0 attribute cannot be applied to a statement">;
|
||||
def err_stmt_attribute_invalid_on_decl : Error<
|
||||
def err_attribute_invalid_on_decl : Error<
|
||||
"%0 attribute cannot be applied to a declaration">;
|
||||
def warn_type_attribute_deprecated_on_decl : Warning<
|
||||
"applying attribute %0 to a declaration is deprecated; apply it to the type instead">,
|
||||
InGroup<DeprecatedAttributes>;
|
||||
def warn_declspec_attribute_ignored : Warning<
|
||||
"attribute %0 is ignored, place it after "
|
||||
"\"%select{class|struct|interface|union|enum}1\" to apply attribute to "
|
||||
|
|
|
@ -2075,7 +2075,8 @@ private:
|
|||
SourceLocation *TrailingElseLoc = nullptr);
|
||||
StmtResult ParseStatementOrDeclarationAfterAttributes(
|
||||
StmtVector &Stmts, ParsedStmtContext StmtCtx,
|
||||
SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs);
|
||||
SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs,
|
||||
ParsedAttributes &DeclSpecAttrs);
|
||||
StmtResult ParseExprStatement(ParsedStmtContext StmtCtx);
|
||||
StmtResult ParseLabeledStatement(ParsedAttributes &Attrs,
|
||||
ParsedStmtContext StmtCtx);
|
||||
|
@ -2324,15 +2325,18 @@ private:
|
|||
|
||||
DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context,
|
||||
SourceLocation &DeclEnd,
|
||||
ParsedAttributes &Attrs,
|
||||
ParsedAttributes &DeclAttrs,
|
||||
ParsedAttributes &DeclSpecAttrs,
|
||||
SourceLocation *DeclSpecStart = nullptr);
|
||||
DeclGroupPtrTy
|
||||
ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
|
||||
ParsedAttributes &Attrs, bool RequireSemi,
|
||||
ParsedAttributes &DeclAttrs,
|
||||
ParsedAttributes &DeclSpecAttrs, bool RequireSemi,
|
||||
ForRangeInit *FRI = nullptr,
|
||||
SourceLocation *DeclSpecStart = nullptr);
|
||||
bool MightBeDeclarator(DeclaratorContext Context);
|
||||
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
|
||||
ParsedAttributes &Attrs,
|
||||
SourceLocation *DeclEnd = nullptr,
|
||||
ForRangeInit *FRI = nullptr);
|
||||
Decl *ParseDeclarationAfterDeclarator(Declarator &D,
|
||||
|
|
|
@ -201,9 +201,11 @@ namespace clang {
|
|||
ParsingDeclRAIIObject ParsingRAII;
|
||||
|
||||
public:
|
||||
ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, DeclaratorContext C)
|
||||
: Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
|
||||
}
|
||||
ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS,
|
||||
const ParsedAttributes &DeclarationAttrs,
|
||||
DeclaratorContext C)
|
||||
: Declarator(DS, DeclarationAttrs, C),
|
||||
ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {}
|
||||
|
||||
const ParsingDeclSpec &getDeclSpec() const {
|
||||
return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
|
||||
|
@ -228,9 +230,10 @@ namespace clang {
|
|||
ParsingDeclRAIIObject ParsingRAII;
|
||||
|
||||
public:
|
||||
ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS)
|
||||
: FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
|
||||
}
|
||||
ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS,
|
||||
const ParsedAttributes &DeclarationAttrs)
|
||||
: FieldDeclarator(DS, DeclarationAttrs),
|
||||
ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {}
|
||||
|
||||
const ParsingDeclSpec &getDeclSpec() const {
|
||||
return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());
|
||||
|
|
|
@ -1852,9 +1852,13 @@ private:
|
|||
/// Indicates whether this declarator has an initializer.
|
||||
unsigned HasInitializer : 1;
|
||||
|
||||
/// Attrs - Attributes.
|
||||
/// Attributes attached to the declarator.
|
||||
ParsedAttributes Attrs;
|
||||
|
||||
/// Attributes attached to the declaration. See also documentation for the
|
||||
/// corresponding constructor parameter.
|
||||
const ParsedAttributesView &DeclarationAttrs;
|
||||
|
||||
/// The asm label, if specified.
|
||||
Expr *AsmLabel;
|
||||
|
||||
|
@ -1893,16 +1897,40 @@ private:
|
|||
friend struct DeclaratorChunk;
|
||||
|
||||
public:
|
||||
Declarator(const DeclSpec &ds, DeclaratorContext C)
|
||||
: DS(ds), Range(ds.getSourceRange()), Context(C),
|
||||
/// `DS` and `DeclarationAttrs` must outlive the `Declarator`. In particular,
|
||||
/// take care not to pass temporary objects for these parameters.
|
||||
///
|
||||
/// `DeclarationAttrs` contains [[]] attributes from the
|
||||
/// attribute-specifier-seq at the beginning of a declaration, which appertain
|
||||
/// to the declared entity itself. Attributes with other syntax (e.g. GNU)
|
||||
/// should not be placed in this attribute list; if they occur at the
|
||||
/// beginning of a declaration, they apply to the `DeclSpec` and should be
|
||||
/// attached to that instead.
|
||||
///
|
||||
/// Here is an example of an attribute associated with a declaration:
|
||||
///
|
||||
/// [[deprecated]] int x, y;
|
||||
///
|
||||
/// This attribute appertains to all of the entities declared in the
|
||||
/// declaration, i.e. `x` and `y` in this case.
|
||||
Declarator(const DeclSpec &DS, const ParsedAttributesView &DeclarationAttrs,
|
||||
DeclaratorContext C)
|
||||
: DS(DS), Range(DS.getSourceRange()), Context(C),
|
||||
InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
|
||||
GroupingParens(false), FunctionDefinition(static_cast<unsigned>(
|
||||
FunctionDefinitionKind::Declaration)),
|
||||
Redeclaration(false), Extension(false), ObjCIvar(false),
|
||||
ObjCWeakProperty(false), InlineStorageUsed(false),
|
||||
HasInitializer(false), Attrs(ds.getAttributePool().getFactory()),
|
||||
AsmLabel(nullptr), TrailingRequiresClause(nullptr),
|
||||
InventedTemplateParameterList(nullptr) {}
|
||||
HasInitializer(false), Attrs(DS.getAttributePool().getFactory()),
|
||||
DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr),
|
||||
TrailingRequiresClause(nullptr),
|
||||
InventedTemplateParameterList(nullptr) {
|
||||
assert(llvm::all_of(DeclarationAttrs,
|
||||
[](const ParsedAttr &AL) {
|
||||
return AL.isStandardAttributeSyntax();
|
||||
}) &&
|
||||
"DeclarationAttrs may only contain [[]] attributes");
|
||||
}
|
||||
|
||||
~Declarator() {
|
||||
clear();
|
||||
|
@ -2531,9 +2559,14 @@ public:
|
|||
const ParsedAttributes &getAttributes() const { return Attrs; }
|
||||
ParsedAttributes &getAttributes() { return Attrs; }
|
||||
|
||||
const ParsedAttributesView &getDeclarationAttributes() const {
|
||||
return DeclarationAttrs;
|
||||
}
|
||||
|
||||
/// hasAttributes - do we contain any attributes?
|
||||
bool hasAttributes() const {
|
||||
if (!getAttributes().empty() || getDeclSpec().hasAttributes())
|
||||
if (!getAttributes().empty() || !getDeclarationAttributes().empty() ||
|
||||
getDeclSpec().hasAttributes())
|
||||
return true;
|
||||
for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i)
|
||||
if (!getTypeObject(i).getAttrs().empty())
|
||||
|
@ -2615,8 +2648,10 @@ public:
|
|||
struct FieldDeclarator {
|
||||
Declarator D;
|
||||
Expr *BitfieldSize;
|
||||
explicit FieldDeclarator(const DeclSpec &DS)
|
||||
: D(DS, DeclaratorContext::Member), BitfieldSize(nullptr) {}
|
||||
explicit FieldDeclarator(const DeclSpec &DS,
|
||||
const ParsedAttributes &DeclarationAttrs)
|
||||
: D(DS, DeclarationAttrs, DeclaratorContext::Member),
|
||||
BitfieldSize(nullptr) {}
|
||||
};
|
||||
|
||||
/// Represents a C++11 virt-specifier-seq.
|
||||
|
|
|
@ -651,6 +651,18 @@ public:
|
|||
bool isKnownToGCC() const;
|
||||
bool isSupportedByPragmaAttribute() const;
|
||||
|
||||
/// Returns whether a [[]] attribute, if specified ahead of a declaration,
|
||||
/// should be applied to the decl-specifier-seq instead (i.e. whether it
|
||||
/// "slides" to the decl-specifier-seq).
|
||||
///
|
||||
/// By the standard, attributes specified before the declaration always
|
||||
/// appertain to the declaration, but historically we have allowed some of
|
||||
/// these attributes to slide to the decl-specifier-seq, so we need to keep
|
||||
/// supporting this behavior.
|
||||
///
|
||||
/// This may only be called if isStandardAttributeSyntax() returns true.
|
||||
bool slidesFromDeclToDeclSpecLegacyBehavior() const;
|
||||
|
||||
/// If the parsed attribute has a semantic equivalent, and it would
|
||||
/// have a semantic Spelling enumeration (due to having semantically-distinct
|
||||
/// spelling variations), return the value of that semantic spelling. If the
|
||||
|
@ -901,6 +913,12 @@ class ParsedAttributesView {
|
|||
|
||||
public:
|
||||
SourceRange Range;
|
||||
|
||||
static const ParsedAttributesView &none() {
|
||||
static const ParsedAttributesView Attrs;
|
||||
return Attrs;
|
||||
}
|
||||
|
||||
bool empty() const { return AttrList.empty(); }
|
||||
SizeType size() const { return AttrList.size(); }
|
||||
ParsedAttr &operator[](SizeType pos) { return *AttrList[pos]; }
|
||||
|
@ -1103,6 +1121,11 @@ private:
|
|||
mutable AttributePool pool;
|
||||
};
|
||||
|
||||
/// Consumes the attributes from `First` and `Second` and concatenates them into
|
||||
/// `Result`. Sets `Result.Range` to the combined range of `First` and `Second`.
|
||||
void takeAndConcatenateAttrs(ParsedAttributes &First, ParsedAttributes &Second,
|
||||
ParsedAttributes &Result);
|
||||
|
||||
/// These constants match the enumerated choices of
|
||||
/// err_attribute_argument_n_type and err_attribute_argument_type.
|
||||
enum AttributeArgumentNType {
|
||||
|
|
|
@ -4429,8 +4429,38 @@ public:
|
|||
// Helper for delayed processing of attributes.
|
||||
void ProcessDeclAttributeDelayed(Decl *D,
|
||||
const ParsedAttributesView &AttrList);
|
||||
void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AL,
|
||||
bool IncludeCXX11Attributes = true);
|
||||
|
||||
// Options for ProcessDeclAttributeList().
|
||||
struct ProcessDeclAttributeOptions {
|
||||
ProcessDeclAttributeOptions()
|
||||
: IncludeCXX11Attributes(true), IgnoreTypeAttributes(false) {}
|
||||
|
||||
ProcessDeclAttributeOptions WithIncludeCXX11Attributes(bool Val) {
|
||||
ProcessDeclAttributeOptions Result = *this;
|
||||
Result.IncludeCXX11Attributes = Val;
|
||||
return Result;
|
||||
}
|
||||
|
||||
ProcessDeclAttributeOptions WithIgnoreTypeAttributes(bool Val) {
|
||||
ProcessDeclAttributeOptions Result = *this;
|
||||
Result.IgnoreTypeAttributes = Val;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Should C++11 attributes be processed?
|
||||
bool IncludeCXX11Attributes;
|
||||
|
||||
// Should any type attributes encountered be ignored?
|
||||
// If this option is false, a diagnostic will be emitted for any type
|
||||
// attributes of a kind that does not "slide" from the declaration to
|
||||
// the decl-specifier-seq.
|
||||
bool IgnoreTypeAttributes;
|
||||
};
|
||||
|
||||
void ProcessDeclAttributeList(Scope *S, Decl *D,
|
||||
const ParsedAttributesView &AttrList,
|
||||
const ProcessDeclAttributeOptions &Options =
|
||||
ProcessDeclAttributeOptions());
|
||||
bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
|
||||
const ParsedAttributesView &AttrList);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, DeclaratorContext Context,
|
|||
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : nullptr;
|
||||
|
||||
// Parse the abstract-declarator, if present.
|
||||
Declarator DeclaratorInfo(DS, Context);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
if (Range)
|
||||
*Range = DeclaratorInfo.getSourceRange();
|
||||
|
@ -1760,7 +1760,8 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs,
|
|||
///
|
||||
Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
|
||||
SourceLocation &DeclEnd,
|
||||
ParsedAttributes &Attrs,
|
||||
ParsedAttributes &DeclAttrs,
|
||||
ParsedAttributes &DeclSpecAttrs,
|
||||
SourceLocation *DeclSpecStart) {
|
||||
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
||||
// Must temporarily exit the objective-c container scope for
|
||||
|
@ -1771,32 +1772,40 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
|
|||
switch (Tok.getKind()) {
|
||||
case tok::kw_template:
|
||||
case tok::kw_export:
|
||||
ProhibitAttributes(Attrs);
|
||||
SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, Attrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
ProhibitAttributes(DeclSpecAttrs);
|
||||
SingleDecl =
|
||||
ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
|
||||
break;
|
||||
case tok::kw_inline:
|
||||
// Could be the start of an inline namespace. Allowed as an ext in C++03.
|
||||
if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
ProhibitAttributes(DeclSpecAttrs);
|
||||
SourceLocation InlineLoc = ConsumeToken();
|
||||
return ParseNamespace(Context, DeclEnd, InlineLoc);
|
||||
}
|
||||
return ParseSimpleDeclaration(Context, DeclEnd, Attrs, true, nullptr,
|
||||
DeclSpecStart);
|
||||
return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
|
||||
true, nullptr, DeclSpecStart);
|
||||
case tok::kw_namespace:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
ProhibitAttributes(DeclSpecAttrs);
|
||||
return ParseNamespace(Context, DeclEnd);
|
||||
case tok::kw_using:
|
||||
case tok::kw_using: {
|
||||
ParsedAttributes Attrs(AttrFactory);
|
||||
takeAndConcatenateAttrs(DeclAttrs, DeclSpecAttrs, Attrs);
|
||||
return ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
|
||||
DeclEnd, Attrs);
|
||||
}
|
||||
case tok::kw_static_assert:
|
||||
case tok::kw__Static_assert:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
ProhibitAttributes(DeclSpecAttrs);
|
||||
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
|
||||
break;
|
||||
default:
|
||||
return ParseSimpleDeclaration(Context, DeclEnd, Attrs, true, nullptr,
|
||||
DeclSpecStart);
|
||||
return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
|
||||
true, nullptr, DeclSpecStart);
|
||||
}
|
||||
|
||||
// This routine returns a DeclGroup, if the thing we parsed only contains a
|
||||
|
@ -1826,10 +1835,17 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
|
|||
/// the Declaration. The SourceLocation for this Decl is set to
|
||||
/// DeclSpecStart if DeclSpecStart is non-null.
|
||||
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
|
||||
DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &Attrs,
|
||||
DeclaratorContext Context, SourceLocation &DeclEnd,
|
||||
ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs,
|
||||
bool RequireSemi, ForRangeInit *FRI, SourceLocation *DeclSpecStart) {
|
||||
// Need to retain these for diagnostics before we add them to the DeclSepc.
|
||||
ParsedAttributesView OriginalDeclSpecAttrs;
|
||||
OriginalDeclSpecAttrs.addAll(DeclSpecAttrs.begin(), DeclSpecAttrs.end());
|
||||
OriginalDeclSpecAttrs.Range = DeclSpecAttrs.Range;
|
||||
|
||||
// Parse the common declaration-specifiers piece.
|
||||
ParsingDeclSpec DS(*this);
|
||||
DS.takeAttributesFrom(DeclSpecAttrs);
|
||||
|
||||
DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
|
||||
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
|
||||
|
@ -1843,7 +1859,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
|
|||
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
|
||||
// declaration-specifiers init-declarator-list[opt] ';'
|
||||
if (Tok.is(tok::semi)) {
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
DeclEnd = Tok.getLocation();
|
||||
if (RequireSemi) ConsumeToken();
|
||||
RecordDecl *AnonRecord = nullptr;
|
||||
|
@ -1860,8 +1876,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
|
|||
if (DeclSpecStart)
|
||||
DS.SetRangeStart(*DeclSpecStart);
|
||||
|
||||
DS.takeAttributesFrom(Attrs);
|
||||
return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
|
||||
return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
|
||||
}
|
||||
|
||||
/// Returns true if this might be the start of a declarator, or a common typo
|
||||
|
@ -2016,10 +2031,16 @@ void Parser::SkipMalformedDecl() {
|
|||
/// result.
|
||||
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
||||
DeclaratorContext Context,
|
||||
ParsedAttributes &Attrs,
|
||||
SourceLocation *DeclEnd,
|
||||
ForRangeInit *FRI) {
|
||||
// Parse the first declarator.
|
||||
ParsingDeclarator D(*this, DS, Context);
|
||||
// Consume all of the attributes from `Attrs` by moving them to our own local
|
||||
// list. This ensures that we will not attempt to interpret them as statement
|
||||
// attributes higher up the callchain.
|
||||
ParsedAttributes LocalAttrs(AttrFactory);
|
||||
LocalAttrs.takeAllFrom(Attrs);
|
||||
ParsingDeclarator D(*this, DS, LocalAttrs, Context);
|
||||
ParseDeclarator(D);
|
||||
|
||||
// Bail out if the first declarator didn't seem well-formed.
|
||||
|
@ -3176,11 +3197,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
if (!AttrsLastTime)
|
||||
ProhibitAttributes(attrs);
|
||||
else {
|
||||
// Reject most C++11 / C2x attributes on the decl-specifier-seq, but
|
||||
// allow `annotate_type` as a special case.
|
||||
// FIXME: We should more generally allow type attributes to be placed
|
||||
// on the decl-specifier-seq; https://reviews.llvm.org/D126061 will
|
||||
// make this change.
|
||||
// Reject C++11 / C2x attributes that aren't type attributes.
|
||||
for (const ParsedAttr &PA : attrs) {
|
||||
if (!PA.isCXX11Attribute() && !PA.isC2xAttribute())
|
||||
continue;
|
||||
|
@ -3188,7 +3205,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// We will warn about the unknown attribute elsewhere (in
|
||||
// SemaDeclAttr.cpp)
|
||||
continue;
|
||||
if (PA.getKind() == ParsedAttr::AT_AnnotateType)
|
||||
// GCC ignores this attribute when placed on the DeclSpec in [[]]
|
||||
// syntax, so we do the same.
|
||||
if (PA.getKind() == ParsedAttr::AT_VectorSize) {
|
||||
Diag(PA.getLoc(), diag::warn_attribute_ignored) << PA;
|
||||
PA.setInvalid();
|
||||
continue;
|
||||
}
|
||||
// We reject AT_LifetimeBound and AT_AnyX86NoCfCheck, even though they
|
||||
// are type attributes, because we historically haven't allowed these
|
||||
// to be used as type attributes in C++11 / C2x syntax.
|
||||
if (PA.isTypeAttr() && PA.getKind() != ParsedAttr::AT_LifetimeBound &&
|
||||
PA.getKind() != ParsedAttr::AT_AnyX86NoCfCheck)
|
||||
continue;
|
||||
Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA;
|
||||
PA.setInvalid();
|
||||
|
@ -4317,7 +4345,6 @@ void Parser::ParseStructDeclaration(
|
|||
// Parse leading attributes.
|
||||
ParsedAttributes Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attrs);
|
||||
DS.takeAttributesFrom(Attrs);
|
||||
|
||||
// Parse the common specifier-qualifiers-list piece.
|
||||
ParseSpecifierQualifierList(DS);
|
||||
|
@ -4325,6 +4352,11 @@ void Parser::ParseStructDeclaration(
|
|||
// If there are no declarators, this is a free-standing declaration
|
||||
// specifier. Let the actions module cope with it.
|
||||
if (Tok.is(tok::semi)) {
|
||||
// C2x 6.7.2.1p9 : "The optional attribute specifier sequence in a
|
||||
// member declaration appertains to each of the members declared by the
|
||||
// member declarator list; it shall not appear if the optional member
|
||||
// declarator list is omitted."
|
||||
ProhibitAttributes(Attrs);
|
||||
RecordDecl *AnonRecord = nullptr;
|
||||
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
|
||||
DS, AnonRecord);
|
||||
|
@ -4337,7 +4369,7 @@ void Parser::ParseStructDeclaration(
|
|||
bool FirstDeclarator = true;
|
||||
SourceLocation CommaLoc;
|
||||
while (true) {
|
||||
ParsingFieldDeclarator DeclaratorInfo(*this, DS);
|
||||
ParsingFieldDeclarator DeclaratorInfo(*this, DS, Attrs);
|
||||
DeclaratorInfo.D.setCommaLoc(CommaLoc);
|
||||
|
||||
// Attributes are only allowed here on successive declarators.
|
||||
|
@ -4696,7 +4728,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
// declares 'enum E : int; E *p;' not 'enum E : int*; E p;'.
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier);
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
||||
|
||||
BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd());
|
||||
|
@ -6618,9 +6651,9 @@ void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
|
|||
/// declarator D up to a paren, which indicates that we are parsing function
|
||||
/// arguments.
|
||||
///
|
||||
/// If FirstArgAttrs is non-null, then the caller parsed those arguments
|
||||
/// immediately after the open paren - they should be considered to be the
|
||||
/// first argument of a parameter.
|
||||
/// If FirstArgAttrs is non-null, then the caller parsed those attributes
|
||||
/// immediately after the open paren - they will be applied to the DeclSpec
|
||||
/// of the first parameter.
|
||||
///
|
||||
/// If RequiresArg is true, then the first argument of the function is required
|
||||
/// to be present and required to not be an identifier list.
|
||||
|
@ -6922,7 +6955,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
|
|||
///
|
||||
/// DeclContext is the context of the declarator being parsed. If FirstArgAttrs
|
||||
/// is non-null, then the caller parsed those attributes immediately after the
|
||||
/// open paren - they should be considered to be part of the first parameter.
|
||||
/// open paren - they will be applied to the DeclSpec of the first parameter.
|
||||
///
|
||||
/// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
|
||||
/// be the location of the ellipsis, if any was parsed.
|
||||
|
@ -6974,29 +7007,33 @@ void Parser::ParseParameterDeclarationClause(
|
|||
// Just use the ParsingDeclaration "scope" of the declarator.
|
||||
DeclSpec DS(AttrFactory);
|
||||
|
||||
ParsedAttributes ArgDeclAttrs(AttrFactory);
|
||||
ParsedAttributes ArgDeclSpecAttrs(AttrFactory);
|
||||
|
||||
if (FirstArgAttrs.Range.isValid()) {
|
||||
// If the caller parsed attributes for the first argument, add them now.
|
||||
// Take them so that we only apply the attributes to the first parameter.
|
||||
// We have already started parsing the decl-specifier sequence, so don't
|
||||
// parse any parameter-declaration pieces that precede it.
|
||||
ArgDeclSpecAttrs.takeAllFrom(FirstArgAttrs);
|
||||
} else {
|
||||
// Parse any C++11 attributes.
|
||||
MaybeParseCXX11Attributes(DS.getAttributes());
|
||||
MaybeParseCXX11Attributes(ArgDeclAttrs);
|
||||
|
||||
// Skip any Microsoft attributes before a param.
|
||||
MaybeParseMicrosoftAttributes(DS.getAttributes());
|
||||
MaybeParseMicrosoftAttributes(ArgDeclSpecAttrs);
|
||||
}
|
||||
|
||||
SourceLocation DSStart = Tok.getLocation();
|
||||
|
||||
// If the caller parsed attributes for the first argument, add them now.
|
||||
// Take them so that we only apply the attributes to the first parameter.
|
||||
// FIXME: If we can leave the attributes in the token stream somehow, we can
|
||||
// get rid of a parameter (FirstArgAttrs) and this statement. It might be
|
||||
// too much hassle.
|
||||
DS.takeAttributesFrom(FirstArgAttrs);
|
||||
|
||||
ParseDeclarationSpecifiers(DS);
|
||||
|
||||
DS.takeAttributesFrom(ArgDeclSpecAttrs);
|
||||
|
||||
// Parse the declarator. This is "PrototypeContext" or
|
||||
// "LambdaExprParameterContext", because we must accept either
|
||||
// 'declarator' or 'abstract-declarator' here.
|
||||
Declarator ParmDeclarator(
|
||||
DS, DeclaratorCtx == DeclaratorContext::RequiresExpr
|
||||
Declarator ParmDeclarator(DS, ArgDeclAttrs,
|
||||
DeclaratorCtx == DeclaratorContext::RequiresExpr
|
||||
? DeclaratorContext::RequiresExpr
|
||||
: DeclaratorCtx == DeclaratorContext::LambdaExpr
|
||||
? DeclaratorContext::LambdaExprParameter
|
||||
|
@ -7299,7 +7336,8 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
|
|||
assert(!D.mayOmitIdentifier() && "Declarator cannot omit identifier");
|
||||
|
||||
SourceLocation StartBracketLoc = Tok.getLocation();
|
||||
Declarator TempDeclarator(D.getDeclSpec(), D.getContext());
|
||||
Declarator TempDeclarator(D.getDeclSpec(), ParsedAttributesView::none(),
|
||||
D.getContext());
|
||||
|
||||
while (Tok.is(tok::l_square)) {
|
||||
ParseBracketDeclarator(TempDeclarator);
|
||||
|
|
|
@ -355,8 +355,8 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
|
|||
getCurScope(), DS.getSourceRange().getBegin(), Lang.get(),
|
||||
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
|
||||
|
||||
ParsedAttributes attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(attrs);
|
||||
ParsedAttributes DeclAttrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(DeclAttrs);
|
||||
|
||||
if (Tok.isNot(tok::l_brace)) {
|
||||
// Reset the source range in DS, as the leading "extern"
|
||||
|
@ -365,7 +365,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
|
|||
DS.SetRangeEnd(SourceLocation());
|
||||
// ... but anyway remember that such an "extern" was seen.
|
||||
DS.setExternInLinkageSpec(true);
|
||||
ParseExternalDeclaration(attrs, &DS);
|
||||
ParseExternalDeclaration(DeclAttrs, &DS);
|
||||
return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
|
||||
getCurScope(), LinkageSpec, SourceLocation())
|
||||
: nullptr;
|
||||
|
@ -373,7 +373,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
|
|||
|
||||
DS.abort();
|
||||
|
||||
ProhibitAttributes(attrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
|
||||
BalancedDelimiterTracker T(*this, tok::l_brace);
|
||||
T.consumeOpen();
|
||||
|
@ -1217,7 +1217,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
|
|||
|
||||
EndLocation = ParseDecltypeSpecifier(DS);
|
||||
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
||||
}
|
||||
|
||||
|
@ -1309,7 +1310,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
|
|||
DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type,
|
||||
Actions.getASTContext().getPrintingPolicy());
|
||||
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
||||
}
|
||||
|
||||
|
@ -2680,23 +2682,15 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
TemplateInfo, TemplateDiags);
|
||||
}
|
||||
|
||||
ParsedAttributes attrs(AttrFactory);
|
||||
ParsedAttributesView FnAttrs;
|
||||
ParsedAttributes DeclAttrs(AttrFactory);
|
||||
// Optional C++11 attribute-specifier
|
||||
MaybeParseCXX11Attributes(attrs);
|
||||
MaybeParseCXX11Attributes(DeclAttrs);
|
||||
|
||||
// The next token may be an OpenMP pragma annotation token. That would
|
||||
// normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in
|
||||
// this case, it came from an *attribute* rather than a pragma. Handle it now.
|
||||
if (Tok.is(tok::annot_attr_openmp))
|
||||
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
|
||||
|
||||
// We need to keep these attributes for future diagnostic
|
||||
// before they are taken over by declaration specifier.
|
||||
FnAttrs.addAll(attrs.begin(), attrs.end());
|
||||
FnAttrs.Range = attrs.Range;
|
||||
|
||||
MaybeParseMicrosoftAttributes(attrs);
|
||||
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, DeclAttrs);
|
||||
|
||||
if (Tok.is(tok::kw_using)) {
|
||||
// Eat 'using'.
|
||||
|
@ -2717,16 +2711,20 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
SourceLocation DeclEnd;
|
||||
// Otherwise, it must be a using-declaration or an alias-declaration.
|
||||
return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo,
|
||||
UsingLoc, DeclEnd, attrs, AS);
|
||||
UsingLoc, DeclEnd, DeclAttrs, AS);
|
||||
}
|
||||
|
||||
ParsedAttributes DeclSpecAttrs(AttrFactory);
|
||||
MaybeParseMicrosoftAttributes(DeclSpecAttrs);
|
||||
|
||||
// Hold late-parsed attributes so we can attach a Decl to them later.
|
||||
LateParsedAttrList CommonLateParsedAttrs;
|
||||
|
||||
// decl-specifier-seq:
|
||||
// Parse the common declaration-specifiers piece.
|
||||
ParsingDeclSpec DS(*this, TemplateDiags);
|
||||
DS.takeAttributesFrom(attrs);
|
||||
DS.takeAttributesFrom(DeclSpecAttrs);
|
||||
|
||||
if (MalformedTypeSpec)
|
||||
DS.SetTypeSpecError();
|
||||
|
||||
|
@ -2764,7 +2762,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
|
||||
if (TryConsumeToken(tok::semi)) {
|
||||
if (DS.isFriendSpecified())
|
||||
ProhibitAttributes(FnAttrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
|
||||
RecordDecl *AnonRecord = nullptr;
|
||||
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(
|
||||
|
@ -2777,7 +2775,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
||||
}
|
||||
|
||||
ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::Member);
|
||||
ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs,
|
||||
DeclaratorContext::Member);
|
||||
if (TemplateInfo.TemplateParams)
|
||||
DeclaratorInfo.setTemplateParameterLists(TemplateParams);
|
||||
VirtSpecifiers VS;
|
||||
|
@ -2869,7 +2868,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
DS.isFriendSpecified()) {
|
||||
// Diagnose attributes that appear before decl specifier:
|
||||
// [[]] friend int foo();
|
||||
ProhibitAttributes(FnAttrs);
|
||||
ProhibitAttributes(DeclAttrs);
|
||||
}
|
||||
|
||||
if (DefinitionKind != FunctionDefinitionKind::Declaration) {
|
||||
|
|
|
@ -1212,7 +1212,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
|||
DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ,
|
||||
Actions.getASTContext().getPrintingPolicy());
|
||||
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
|
||||
DeclaratorInfo);
|
||||
if (Ty.isInvalid())
|
||||
|
@ -1490,7 +1491,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
|||
PrevSpec, DiagID, Type,
|
||||
Actions.getASTContext().getPrintingPolicy());
|
||||
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
||||
if (Ty.isInvalid())
|
||||
break;
|
||||
|
@ -2296,7 +2298,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
|
|||
if (isTypeIdUnambiguously()) {
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseSpecifierQualifierList(DS);
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation());
|
||||
|
@ -2959,7 +2962,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
|||
// Parse the type declarator.
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseSpecifierQualifierList(DS);
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
// If our type is followed by an identifier and either ':' or ']', then
|
||||
|
@ -3494,7 +3498,8 @@ void Parser::ParseBlockId(SourceLocation CaretLoc) {
|
|||
ParseSpecifierQualifierList(DS);
|
||||
|
||||
// Parse the block-declarator.
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteral);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::BlockLiteral);
|
||||
DeclaratorInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
|
@ -3533,7 +3538,8 @@ ExprResult Parser::ParseBlockLiteralExpression() {
|
|||
|
||||
// Parse the return type if present.
|
||||
DeclSpec DS(AttrFactory);
|
||||
Declarator ParamInfo(DS, DeclaratorContext::BlockLiteral);
|
||||
Declarator ParamInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::BlockLiteral);
|
||||
ParamInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
|
||||
// FIXME: Since the return type isn't actually parsed, it can't be used to
|
||||
// fill ParamInfo with an initial valid range, so do it manually.
|
||||
|
|
|
@ -1248,7 +1248,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
|
||||
// Parse lambda-declarator[opt].
|
||||
DeclSpec DS(AttrFactory);
|
||||
Declarator D(DS, DeclaratorContext::LambdaExpr);
|
||||
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::LambdaExpr);
|
||||
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
|
||||
Actions.PushLambdaScope();
|
||||
|
||||
|
@ -1523,7 +1523,8 @@ ExprResult Parser::ParseCXXCasts() {
|
|||
ParseSpecifierQualifierList(DS);
|
||||
|
||||
// Parse the abstract-declarator, if present.
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
SourceLocation RAngleBracketLoc = Tok.getLocation();
|
||||
|
@ -1849,7 +1850,8 @@ ExprResult Parser::ParseCXXThis() {
|
|||
/// In C++1z onwards, the type specifier can also be a template-name.
|
||||
ExprResult
|
||||
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::FunctionalCast);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::FunctionalCast);
|
||||
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
|
||||
|
||||
assert((Tok.is(tok::l_paren) ||
|
||||
|
@ -2048,9 +2050,11 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
|||
if (Tok.is(tok::kw_using))
|
||||
DG = ParseAliasDeclarationInInitStatement(
|
||||
DeclaratorContext::SelectionInit, attrs);
|
||||
else
|
||||
else {
|
||||
ParsedAttributes DeclSpecAttrs(AttrFactory);
|
||||
DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd,
|
||||
attrs, /*RequireSemi=*/true);
|
||||
attrs, DeclSpecAttrs, /*RequireSemi=*/true);
|
||||
}
|
||||
*InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
|
||||
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
|
||||
}
|
||||
|
@ -2061,8 +2065,9 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
|||
// permitted here.
|
||||
assert(FRI && "should not parse a for range declaration here");
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
DeclGroupPtrTy DG = ParseSimpleDeclaration(DeclaratorContext::ForInit,
|
||||
DeclEnd, attrs, false, FRI);
|
||||
ParsedAttributes DeclSpecAttrs(AttrFactory);
|
||||
DeclGroupPtrTy DG = ParseSimpleDeclaration(
|
||||
DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false, FRI);
|
||||
FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
|
||||
assert((FRI->ColonLoc.isValid() || !DG) &&
|
||||
"cannot find for range declaration");
|
||||
|
@ -2079,11 +2084,10 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
|||
|
||||
// type-specifier-seq
|
||||
DeclSpec DS(AttrFactory);
|
||||
DS.takeAttributesFrom(attrs);
|
||||
ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition);
|
||||
|
||||
// declarator
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::Condition);
|
||||
Declarator DeclaratorInfo(DS, attrs, DeclaratorContext::Condition);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
// simple-asm-expr[opt]
|
||||
|
@ -2736,7 +2740,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
|||
|
||||
// Parse the conversion-declarator, which is merely a sequence of
|
||||
// ptr-operators.
|
||||
Declarator D(DS, DeclaratorContext::ConversionId);
|
||||
Declarator D(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::ConversionId);
|
||||
ParseDeclaratorInternal(D, /*DirectDeclParser=*/nullptr);
|
||||
|
||||
// Finish up the type.
|
||||
|
@ -3094,7 +3099,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
|
|||
|
||||
SourceRange TypeIdParens;
|
||||
DeclSpec DS(AttrFactory);
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::CXXNew);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::CXXNew);
|
||||
if (Tok.is(tok::l_paren)) {
|
||||
// If it turns out to be a placement, we change the type location.
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
|
@ -3945,7 +3951,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
|
|||
if (ParseAs >= CompoundLiteral) {
|
||||
// Parse the type declarator.
|
||||
DeclSpec DS(AttrFactory);
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
{
|
||||
ColonProtectionRAIIObject InnerColonProtection(*this);
|
||||
ParseSpecifierQualifierList(DS);
|
||||
|
@ -4023,7 +4030,8 @@ ExprResult Parser::ParseBuiltinBitCast() {
|
|||
ParseSpecifierQualifierList(DS);
|
||||
|
||||
// Parse the abstract-declarator, if present.
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
if (ExpectAndConsume(tok::comma)) {
|
||||
|
|
|
@ -650,19 +650,21 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
|
|||
if (Tok.is(tok::r_brace))
|
||||
break;
|
||||
|
||||
ParsedAttributes attrs(AttrFactory);
|
||||
ParsedAttributes EmptyAttrs(AttrFactory);
|
||||
|
||||
// Since we call ParseDeclarationOrFunctionDefinition() instead of
|
||||
// ParseExternalDeclaration() below (so that this doesn't parse nested
|
||||
// @interfaces), this needs to duplicate some code from the latter.
|
||||
if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
|
||||
SourceLocation DeclEnd;
|
||||
allTUVariables.push_back(
|
||||
ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs));
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
allTUVariables.push_back(ParseDeclaration(
|
||||
DeclaratorContext::File, DeclEnd, EmptyAttrs, EmptyDeclSpecAttrs));
|
||||
continue;
|
||||
}
|
||||
|
||||
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs));
|
||||
allTUVariables.push_back(
|
||||
ParseDeclarationOrFunctionDefinition(EmptyAttrs));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1225,6 +1227,10 @@ static void takeDeclAttributes(ParsedAttributesView &attrs,
|
|||
/// declarator and add them to the given list.
|
||||
static void takeDeclAttributes(ParsedAttributes &attrs,
|
||||
Declarator &D) {
|
||||
// This gets called only from Parser::ParseObjCTypeName(), and that should
|
||||
// never add declaration attributes to the Declarator.
|
||||
assert(D.getDeclarationAttributes().empty());
|
||||
|
||||
// First, take ownership of all attributes.
|
||||
attrs.getPool().takeAllFrom(D.getAttributePool());
|
||||
attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool());
|
||||
|
@ -1268,7 +1274,7 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
|
|||
if (context == DeclaratorContext::ObjCResult)
|
||||
dsContext = DeclSpecContext::DSC_objc_method_result;
|
||||
ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
|
||||
Declarator declarator(declSpec, context);
|
||||
Declarator declarator(declSpec, ParsedAttributesView::none(), context);
|
||||
ParseDeclarator(declarator);
|
||||
|
||||
// If that's not invalid, extract a type.
|
||||
|
@ -1487,7 +1493,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
|||
DeclSpec DS(AttrFactory);
|
||||
ParseDeclarationSpecifiers(DS);
|
||||
// Parse the declarator.
|
||||
Declarator ParmDecl(DS, DeclaratorContext::Prototype);
|
||||
Declarator ParmDecl(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::Prototype);
|
||||
ParseDeclarator(ParmDecl);
|
||||
IdentifierInfo *ParmII = ParmDecl.getIdentifier();
|
||||
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
|
||||
|
@ -1693,7 +1700,8 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers(
|
|||
typeArg, Actions.getASTContext().getPrintingPolicy());
|
||||
|
||||
// Form a declarator to turn this into a type.
|
||||
Declarator D(DS, DeclaratorContext::TypeName);
|
||||
Declarator D(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
|
||||
if (fullTypeArg.isUsable()) {
|
||||
typeArgs.push_back(fullTypeArg.get());
|
||||
|
@ -2538,7 +2546,8 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
|||
if (Tok.isNot(tok::ellipsis)) {
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseDeclarationSpecifiers(DS);
|
||||
Declarator ParmDecl(DS, DeclaratorContext::ObjCCatch);
|
||||
Declarator ParmDecl(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::ObjCCatch);
|
||||
ParseDeclarator(ParmDecl);
|
||||
|
||||
// Inform the actions module about the declarator, so it
|
||||
|
@ -2954,7 +2963,8 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
|
|||
// We have a class message. Turn the simple-type-specifier or
|
||||
// typename-specifier we parsed into a type and parse the
|
||||
// remainder of the class message.
|
||||
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TypeName);
|
||||
TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
||||
if (Type.isInvalid())
|
||||
return true;
|
||||
|
|
|
@ -639,7 +639,7 @@ TypeResult Parser::parseOpenMPDeclareMapperVarDecl(SourceRange &Range,
|
|||
|
||||
// Parse the declarator.
|
||||
DeclaratorContext Context = DeclaratorContext::Prototype;
|
||||
Declarator DeclaratorInfo(DS, Context);
|
||||
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(), Context);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
Range = DeclaratorInfo.getSourceRange();
|
||||
if (DeclaratorInfo.getIdentifier() == nullptr) {
|
||||
|
|
|
@ -105,15 +105,21 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
|
|||
// statement are different from [[]] attributes that follow an __attribute__
|
||||
// at the start of the statement. Thus, we're not using MaybeParseAttributes
|
||||
// here because we don't want to allow arbitrary orderings.
|
||||
ParsedAttributes Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attrs, /*MightBeObjCMessageSend*/ true);
|
||||
ParsedAttributes CXX11Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
|
||||
ParsedAttributes GNUAttrs(AttrFactory);
|
||||
if (getLangOpts().OpenCL)
|
||||
MaybeParseGNUAttributes(Attrs);
|
||||
MaybeParseGNUAttributes(GNUAttrs);
|
||||
|
||||
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
|
||||
Stmts, StmtCtx, TrailingElseLoc, Attrs);
|
||||
Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUAttrs);
|
||||
MaybeDestroyTemplateIds();
|
||||
|
||||
// Attributes that are left should all go on the statement, so concatenate the
|
||||
// two lists.
|
||||
ParsedAttributes Attrs(AttrFactory);
|
||||
takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs);
|
||||
|
||||
assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
|
||||
"attributes on empty statement");
|
||||
|
||||
|
@ -158,7 +164,8 @@ private:
|
|||
|
||||
StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
|
||||
StmtVector &Stmts, ParsedStmtContext StmtCtx,
|
||||
SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs) {
|
||||
SourceLocation *TrailingElseLoc, ParsedAttributes &CXX11Attrs,
|
||||
ParsedAttributes &GNUAttrs) {
|
||||
const char *SemiError = nullptr;
|
||||
StmtResult Res;
|
||||
SourceLocation GNUAttributeLoc;
|
||||
|
@ -184,6 +191,12 @@ Retry:
|
|||
case tok::identifier: {
|
||||
Token Next = NextToken();
|
||||
if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
|
||||
// Both C++11 and GNU attributes preceding the label appertain to the
|
||||
// label, so put them in a single list to pass on to
|
||||
// ParseLabeledStatement().
|
||||
ParsedAttributes Attrs(AttrFactory);
|
||||
takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs);
|
||||
|
||||
// identifier ':' statement
|
||||
return ParseLabeledStatement(Attrs, StmtCtx);
|
||||
}
|
||||
|
@ -213,25 +226,33 @@ Retry:
|
|||
}
|
||||
|
||||
default: {
|
||||
bool HaveAttrs = !CXX11Attrs.empty() || !GNUAttrs.empty();
|
||||
auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); };
|
||||
bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) &&
|
||||
llvm::all_of(GNUAttrs, IsStmtAttr);
|
||||
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
|
||||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
|
||||
ParsedStmtContext()) &&
|
||||
((GNUAttributeLoc.isValid() &&
|
||||
!(!Attrs.empty() &&
|
||||
llvm::all_of(
|
||||
Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) ||
|
||||
((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) ||
|
||||
isDeclarationStatement())) {
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
DeclGroupPtrTy Decl;
|
||||
if (GNUAttributeLoc.isValid()) {
|
||||
DeclStart = GNUAttributeLoc;
|
||||
Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs,
|
||||
&GNUAttributeLoc);
|
||||
Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs,
|
||||
GNUAttrs, &GNUAttributeLoc);
|
||||
} else {
|
||||
Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs);
|
||||
Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs,
|
||||
GNUAttrs);
|
||||
}
|
||||
if (Attrs.Range.getBegin().isValid())
|
||||
DeclStart = Attrs.Range.getBegin();
|
||||
if (CXX11Attrs.Range.getBegin().isValid()) {
|
||||
// The caller must guarantee that the CXX11Attrs appear before the
|
||||
// GNUAttrs, and we rely on that here.
|
||||
assert(GNUAttrs.Range.getBegin().isInvalid() ||
|
||||
GNUAttrs.Range.getBegin() > CXX11Attrs.Range.getBegin());
|
||||
DeclStart = CXX11Attrs.Range.getBegin();
|
||||
} else if (GNUAttrs.Range.getBegin().isValid())
|
||||
DeclStart = GNUAttrs.Range.getBegin();
|
||||
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
|
||||
}
|
||||
|
||||
|
@ -245,7 +266,7 @@ Retry:
|
|||
|
||||
case tok::kw___attribute: {
|
||||
GNUAttributeLoc = Tok.getLocation();
|
||||
ParseGNUAttributes(Attrs);
|
||||
ParseGNUAttributes(GNUAttrs);
|
||||
goto Retry;
|
||||
}
|
||||
|
||||
|
@ -297,7 +318,11 @@ Retry:
|
|||
break;
|
||||
|
||||
case tok::kw_asm: {
|
||||
ProhibitAttributes(Attrs);
|
||||
for (const ParsedAttr &AL : CXX11Attrs)
|
||||
Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL;
|
||||
// Prevent these from being interpreted as statement attributes later on.
|
||||
CXX11Attrs.clear();
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
bool msAsm = false;
|
||||
Res = ParseAsmStatement(msAsm);
|
||||
Res = Actions.ActOnFinishFullStmt(Res.get());
|
||||
|
@ -308,7 +333,8 @@ Retry:
|
|||
|
||||
case tok::kw___if_exists:
|
||||
case tok::kw___if_not_exists:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
ParseMicrosoftIfExistsStatement(Stmts);
|
||||
// An __if_exists block is like a compound statement, but it doesn't create
|
||||
// a new scope.
|
||||
|
@ -318,7 +344,8 @@ Retry:
|
|||
return ParseCXXTryBlock();
|
||||
|
||||
case tok::kw___try:
|
||||
ProhibitAttributes(Attrs); // TODO: is it correct?
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
return ParseSEHTryBlock();
|
||||
|
||||
case tok::kw___leave:
|
||||
|
@ -327,55 +354,65 @@ Retry:
|
|||
break;
|
||||
|
||||
case tok::annot_pragma_vis:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaVisibility();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_pack:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaPack();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_msstruct:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaMSStruct();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_align:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaAlign();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_weak:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaWeak();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_weakalias:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaWeakAlias();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_redefine_extname:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaRedefineExtname();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_fp_contract:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
|
||||
ConsumeAnnotationToken();
|
||||
return StmtError();
|
||||
|
||||
case tok::annot_pragma_fp:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
|
||||
ConsumeAnnotationToken();
|
||||
return StmtError();
|
||||
|
||||
case tok::annot_pragma_fenv_access:
|
||||
case tok::annot_pragma_fenv_access_ms:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope)
|
||||
<< (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS"
|
||||
: "fenv_access");
|
||||
|
@ -383,53 +420,62 @@ Retry:
|
|||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_fenv_round:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC FENV_ROUND";
|
||||
ConsumeAnnotationToken();
|
||||
return StmtError();
|
||||
|
||||
case tok::annot_pragma_float_control:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
|
||||
ConsumeAnnotationToken();
|
||||
return StmtError();
|
||||
|
||||
case tok::annot_pragma_opencl_extension:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaOpenCLExtension();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_captured:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
return HandlePragmaCaptured();
|
||||
|
||||
case tok::annot_pragma_openmp:
|
||||
// Prohibit attributes that are not OpenMP attributes, but only before
|
||||
// processing a #pragma omp clause.
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
LLVM_FALLTHROUGH;
|
||||
case tok::annot_attr_openmp:
|
||||
// Do not prohibit attributes if they were OpenMP attributes.
|
||||
return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
|
||||
|
||||
case tok::annot_pragma_ms_pointers_to_members:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaMSPointersToMembers();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_ms_pragma:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaMSPragma();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_ms_vtordisp:
|
||||
ProhibitAttributes(Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
HandlePragmaMSVtorDisp();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_loop_hint:
|
||||
ProhibitAttributes(Attrs);
|
||||
return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs);
|
||||
ProhibitAttributes(CXX11Attrs);
|
||||
ProhibitAttributes(GNUAttrs);
|
||||
return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs);
|
||||
|
||||
case tok::annot_pragma_dump:
|
||||
HandlePragmaDump();
|
||||
|
@ -658,8 +704,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
|
|||
Attrs.takeAllFrom(TempAttrs);
|
||||
else {
|
||||
StmtVector Stmts;
|
||||
SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx,
|
||||
nullptr, TempAttrs);
|
||||
ParsedAttributes EmptyCXX11Attrs(AttrFactory);
|
||||
SubStmt = ParseStatementOrDeclarationAfterAttributes(
|
||||
Stmts, StmtCtx, nullptr, EmptyCXX11Attrs, TempAttrs);
|
||||
if (!TempAttrs.empty() && !SubStmt.isInvalid())
|
||||
SubStmt = Actions.ActOnAttributedStmt(TempAttrs, SubStmt.get());
|
||||
}
|
||||
|
@ -1128,8 +1175,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
|||
ExtensionRAIIObject O(Diags);
|
||||
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
DeclGroupPtrTy Res =
|
||||
ParseDeclaration(DeclaratorContext::Block, DeclEnd, attrs);
|
||||
ParsedAttributes DeclSpecAttrs(AttrFactory);
|
||||
DeclGroupPtrTy Res = ParseDeclaration(DeclaratorContext::Block, DeclEnd,
|
||||
attrs, DeclSpecAttrs);
|
||||
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
|
||||
} else {
|
||||
// Otherwise this was a unary __extension__ marker.
|
||||
|
@ -1975,8 +2023,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
|||
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
|
||||
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
ParsedAttributes DeclSpecAttrs(AttrFactory);
|
||||
DG = ParseSimpleDeclaration(
|
||||
DeclaratorContext::ForInit, DeclEnd, attrs, false,
|
||||
DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false,
|
||||
MightBeForRangeStmt ? &ForRangeInfo : nullptr);
|
||||
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
|
||||
if (ForRangeInfo.ParsedForRangeDecl()) {
|
||||
|
@ -2347,8 +2396,9 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
|
|||
// Get the next statement.
|
||||
MaybeParseCXX11Attributes(Attrs);
|
||||
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
StmtResult S = ParseStatementOrDeclarationAfterAttributes(
|
||||
Stmts, StmtCtx, TrailingElseLoc, Attrs);
|
||||
Stmts, StmtCtx, TrailingElseLoc, Attrs, EmptyDeclSpecAttrs);
|
||||
|
||||
Attrs.takeAllFrom(TempAttrs);
|
||||
|
||||
|
@ -2584,12 +2634,11 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
|
|||
MaybeParseCXX11Attributes(Attributes);
|
||||
|
||||
DeclSpec DS(AttrFactory);
|
||||
DS.takeAttributesFrom(Attributes);
|
||||
|
||||
if (ParseCXXTypeSpecifierSeq(DS))
|
||||
return StmtError();
|
||||
|
||||
Declarator ExDecl(DS, DeclaratorContext::CXXCatch);
|
||||
Declarator ExDecl(DS, Attributes, DeclaratorContext::CXXCatch);
|
||||
ParseDeclarator(ExDecl);
|
||||
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
|
||||
} else
|
||||
|
|
|
@ -245,11 +245,10 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
|
|||
// Move the attributes from the prefix into the DS.
|
||||
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
||||
ProhibitAttributes(prefixAttrs);
|
||||
else
|
||||
DS.takeAttributesFrom(prefixAttrs);
|
||||
|
||||
// Parse the declarator.
|
||||
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
|
||||
ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs,
|
||||
(DeclaratorContext)Context);
|
||||
if (TemplateInfo.TemplateParams)
|
||||
DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
|
||||
|
||||
|
@ -669,7 +668,8 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
|
|||
// probably meant to write the type of a NTTP.
|
||||
DeclSpec DS(getAttrFactory());
|
||||
DS.SetTypeSpecError();
|
||||
Declarator D(DS, DeclaratorContext::TemplateParam);
|
||||
Declarator D(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TemplateParam);
|
||||
D.SetIdentifier(nullptr, Tok.getLocation());
|
||||
D.setInvalidType(true);
|
||||
NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter(
|
||||
|
@ -993,7 +993,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
|
|||
DeclSpecContext::DSC_template_param);
|
||||
|
||||
// Parse this as a typename.
|
||||
Declarator ParamDecl(DS, DeclaratorContext::TemplateParam);
|
||||
Declarator ParamDecl(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::TemplateParam);
|
||||
ParseDeclarator(ParamDecl);
|
||||
if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
|
||||
Diag(Tok.getLocation(), diag::err_expected_template_parameter);
|
||||
|
|
|
@ -740,6 +740,9 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
|
|||
|
||||
/// ParseExternalDeclaration:
|
||||
///
|
||||
/// The `Attrs` that are passed in are C++11 attributes and appertain to the
|
||||
/// declaration.
|
||||
///
|
||||
/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
|
||||
/// function-definition
|
||||
/// declaration
|
||||
|
@ -929,7 +932,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
|
|||
// A function definition cannot start with any of these keywords.
|
||||
{
|
||||
SourceLocation DeclEnd;
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
|
||||
EmptyDeclSpecAttrs);
|
||||
}
|
||||
|
||||
case tok::kw_static:
|
||||
|
@ -939,7 +944,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
|
|||
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
|
||||
<< 0;
|
||||
SourceLocation DeclEnd;
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
|
||||
EmptyDeclSpecAttrs);
|
||||
}
|
||||
goto dont_know;
|
||||
|
||||
|
@ -950,7 +957,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
|
|||
// Inline namespaces. Allowed as an extension even in C++03.
|
||||
if (NextKind == tok::kw_namespace) {
|
||||
SourceLocation DeclEnd;
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
|
||||
EmptyDeclSpecAttrs);
|
||||
}
|
||||
|
||||
// Parse (then ignore) 'inline' prior to a template instantiation. This is
|
||||
|
@ -959,7 +968,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
|
|||
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
|
||||
<< 1;
|
||||
SourceLocation DeclEnd;
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
|
||||
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
|
||||
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
|
||||
EmptyDeclSpecAttrs);
|
||||
}
|
||||
}
|
||||
goto dont_know;
|
||||
|
@ -1112,8 +1123,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
|
|||
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
||||
}
|
||||
|
||||
DS.takeAttributesFrom(Attrs);
|
||||
|
||||
// ObjC2 allows prefix attributes on class interfaces and protocols.
|
||||
// FIXME: This still needs better diagnostics. We should only accept
|
||||
// attributes here, no types, etc.
|
||||
|
@ -1128,6 +1137,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
|
|||
}
|
||||
|
||||
DS.abort();
|
||||
DS.takeAttributesFrom(Attrs);
|
||||
|
||||
const char *PrevSpec = nullptr;
|
||||
unsigned DiagID;
|
||||
|
@ -1151,11 +1161,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
|
|||
if (getLangOpts().CPlusPlus && isTokenStringLiteral() &&
|
||||
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
|
||||
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
|
||||
ProhibitAttributes(Attrs);
|
||||
Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File);
|
||||
return Actions.ConvertDeclToDeclGroup(TheDecl);
|
||||
}
|
||||
|
||||
return ParseDeclGroup(DS, DeclaratorContext::File);
|
||||
return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
|
||||
}
|
||||
|
||||
Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
|
||||
|
@ -1473,7 +1484,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
|
|||
}
|
||||
|
||||
// Parse the first declarator attached to this declspec.
|
||||
Declarator ParmDeclarator(DS, DeclaratorContext::KNRTypeList);
|
||||
Declarator ParmDeclarator(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::KNRTypeList);
|
||||
ParseDeclarator(ParmDeclarator);
|
||||
|
||||
// Handle the full declarator list.
|
||||
|
|
|
@ -212,6 +212,39 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const {
|
|||
return getInfo().IsSupportedByPragmaAttribute;
|
||||
}
|
||||
|
||||
bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
|
||||
assert(isStandardAttributeSyntax());
|
||||
|
||||
// We have historically allowed some type attributes with standard attribute
|
||||
// syntax to slide to the decl-specifier-seq, so we have to keep supporting
|
||||
// it. This property is consciously not defined as a flag in Attr.td because
|
||||
// we don't want new attributes to specify it.
|
||||
//
|
||||
// Note: No new entries should be added to this list. Entries should be
|
||||
// removed from this list after a suitable deprecation period, provided that
|
||||
// there are no compatibility considerations with other compilers. If
|
||||
// possible, we would like this list to go away entirely.
|
||||
switch (getParsedKind()) {
|
||||
case AT_AddressSpace:
|
||||
case AT_OpenCLPrivateAddressSpace:
|
||||
case AT_OpenCLGlobalAddressSpace:
|
||||
case AT_OpenCLGlobalDeviceAddressSpace:
|
||||
case AT_OpenCLGlobalHostAddressSpace:
|
||||
case AT_OpenCLLocalAddressSpace:
|
||||
case AT_OpenCLConstantAddressSpace:
|
||||
case AT_OpenCLGenericAddressSpace:
|
||||
case AT_NeonPolyVectorType:
|
||||
case AT_NeonVectorType:
|
||||
case AT_ArmMveStrictPolymorphism:
|
||||
case AT_BTFTypeTag:
|
||||
case AT_ObjCGC:
|
||||
case AT_MatrixType:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
|
||||
|
||||
unsigned ParsedAttr::getSemanticSpelling() const {
|
||||
|
@ -265,3 +298,20 @@ bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
|
|||
diag::err_attribute_too_many_arguments,
|
||||
std::greater<unsigned>());
|
||||
}
|
||||
|
||||
void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
|
||||
ParsedAttributes &Second,
|
||||
ParsedAttributes &Result) {
|
||||
// Note that takeAllFrom() puts the attributes at the beginning of the list,
|
||||
// so to obtain the correct ordering, we add `Second`, then `First`.
|
||||
Result.takeAllFrom(Second);
|
||||
Result.takeAllFrom(First);
|
||||
if (First.Range.getBegin().isValid())
|
||||
Result.Range.setBegin(First.Range.getBegin());
|
||||
else
|
||||
Result.Range.setBegin(Second.Range.getBegin());
|
||||
if (Second.Range.getEnd().isValid())
|
||||
Result.Range.setEnd(Second.Range.getEnd());
|
||||
else
|
||||
Result.Range.setEnd(First.Range.getEnd());
|
||||
}
|
||||
|
|
|
@ -5461,7 +5461,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
|||
Diag(DS.getBeginLoc(), diag::ext_no_declarators) << DS.getSourceRange();
|
||||
|
||||
// Mock up a declarator.
|
||||
Declarator Dc(DS, DeclaratorContext::Member);
|
||||
Declarator Dc(DS, ParsedAttributesView::none(), DeclaratorContext::Member);
|
||||
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
|
||||
assert(TInfo && "couldn't build declarator info for anonymous struct/union");
|
||||
|
||||
|
@ -5558,7 +5558,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
|
|||
assert(Record && "expected a record!");
|
||||
|
||||
// Mock up a declarator.
|
||||
Declarator Dc(DS, DeclaratorContext::TypeName);
|
||||
Declarator Dc(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName);
|
||||
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
|
||||
assert(TInfo && "couldn't build declarator info for anonymous struct");
|
||||
|
||||
|
@ -7000,7 +7000,8 @@ static bool hasParsedAttr(Scope *S, const Declarator &PD,
|
|||
}
|
||||
|
||||
// Finally, check attributes on the decl itself.
|
||||
return PD.getAttributes().hasAttribute(Kind);
|
||||
return PD.getAttributes().hasAttribute(Kind) ||
|
||||
PD.getDeclarationAttributes().hasAttribute(Kind);
|
||||
}
|
||||
|
||||
/// Adjust the \c DeclContext for a function or variable that might be a
|
||||
|
@ -13332,7 +13333,7 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
|
|||
DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID,
|
||||
getPrintingPolicy());
|
||||
|
||||
Declarator D(DS, DeclaratorContext::ForInit);
|
||||
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::ForInit);
|
||||
D.SetIdentifier(Ident, IdentLoc);
|
||||
D.takeAttributes(Attrs);
|
||||
|
||||
|
@ -14330,7 +14331,8 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
|
|||
// Use the identifier location for the type source range.
|
||||
DS.SetRangeStart(FTI.Params[i].IdentLoc);
|
||||
DS.SetRangeEnd(FTI.Params[i].IdentLoc);
|
||||
Declarator ParamD(DS, DeclaratorContext::KNRTypeList);
|
||||
Declarator ParamD(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::KNRTypeList);
|
||||
ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc);
|
||||
FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD);
|
||||
}
|
||||
|
@ -15352,7 +15354,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
|
|||
(void)Error; // Silence warning.
|
||||
assert(!Error && "Error setting up implicit decl!");
|
||||
SourceLocation NoLoc;
|
||||
Declarator D(DS, DeclaratorContext::Block);
|
||||
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::Block);
|
||||
D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
|
||||
/*IsAmbiguous=*/false,
|
||||
/*LParenLoc=*/NoLoc,
|
||||
|
|
|
@ -8316,15 +8316,21 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
|
|||
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
|
||||
/// the attribute applies to decls. If the attribute is a type attribute, just
|
||||
/// silently ignore it if a GNU attribute.
|
||||
static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
||||
const ParsedAttr &AL,
|
||||
bool IncludeCXX11Attributes) {
|
||||
static void
|
||||
ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
|
||||
const Sema::ProcessDeclAttributeOptions &Options) {
|
||||
if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
|
||||
return;
|
||||
|
||||
// Ignore C++11 attributes on declarator chunks: they appertain to the type
|
||||
// instead.
|
||||
if (AL.isCXX11Attribute() && !IncludeCXX11Attributes)
|
||||
// FIXME: We currently check the attribute syntax directly instead of using
|
||||
// isCXX11Attribute(), which currently erroneously classifies the C11
|
||||
// `_Alignas` attribute as a C++11 attribute. `_Alignas` can appear on the
|
||||
// `DeclSpec`, so we need to let it through here to make sure it is processed
|
||||
// appropriately. Once the behavior of isCXX11Attribute() is fixed, we can
|
||||
// go back to using that here.
|
||||
if (AL.getSyntax() == ParsedAttr::AS_CXX11 && !Options.IncludeCXX11Attributes)
|
||||
return;
|
||||
|
||||
// Unknown attributes are automatically warned on. Target-specific attributes
|
||||
|
@ -8357,14 +8363,76 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled)
|
||||
break;
|
||||
if (!AL.isStmtAttr()) {
|
||||
// Type attributes are handled elsewhere; silently move on.
|
||||
assert(AL.isTypeAttr() && "Non-type attribute not handled");
|
||||
}
|
||||
if (AL.isTypeAttr()) {
|
||||
if (Options.IgnoreTypeAttributes)
|
||||
break;
|
||||
if (!AL.isStandardAttributeSyntax()) {
|
||||
// Non-[[]] type attributes are handled in processTypeAttrs(); silently
|
||||
// move on.
|
||||
break;
|
||||
}
|
||||
|
||||
// According to the C and C++ standards, we should never see a
|
||||
// [[]] type attribute on a declaration. However, we have in the past
|
||||
// allowed some type attributes to "slide" to the `DeclSpec`, so we need
|
||||
// to continue to support this legacy behavior. We only do this, however,
|
||||
// if
|
||||
// - we actually have a `DeclSpec`, i.e. if we're looking at a
|
||||
// `DeclaratorDecl`, or
|
||||
// - we are looking at an alias-declaration, where historically we have
|
||||
// allowed type attributes after the identifier to slide to the type.
|
||||
if (AL.slidesFromDeclToDeclSpecLegacyBehavior() &&
|
||||
isa<DeclaratorDecl, TypeAliasDecl>(D)) {
|
||||
// Suggest moving the attribute to the type instead, but only for our
|
||||
// own vendor attributes; moving other vendors' attributes might hurt
|
||||
// portability.
|
||||
if (AL.isClangScope()) {
|
||||
S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
|
||||
<< AL << D->getLocation();
|
||||
}
|
||||
|
||||
// Allow this type attribute to be handled in processTypeAttrs();
|
||||
// silently move on.
|
||||
break;
|
||||
}
|
||||
|
||||
if (AL.getKind() == ParsedAttr::AT_Regparm) {
|
||||
// `regparm` is a special case: It's a type attribute but we still want
|
||||
// to treat it as if it had been written on the declaration because that
|
||||
// way we'll be able to handle it directly in `processTypeAttr()`.
|
||||
// If we treated `regparm` it as if it had been written on the
|
||||
// `DeclSpec`, the logic in `distributeFunctionTypeAttrFromDeclSepc()`
|
||||
// would try to move it to the declarator, but that doesn't work: We
|
||||
// can't remove the attribute from the list of declaration attributes
|
||||
// because it might be needed by other declarators in the same
|
||||
// declaration.
|
||||
break;
|
||||
}
|
||||
|
||||
if (AL.getKind() == ParsedAttr::AT_VectorSize) {
|
||||
// `vector_size` is a special case: It's a type attribute semantically,
|
||||
// but GCC expects the [[]] syntax to be written on the declaration (and
|
||||
// warns that the attribute has no effect if it is placed on the
|
||||
// decl-specifier-seq).
|
||||
// Silently move on and allow the attribute to be handled in
|
||||
// processTypeAttr().
|
||||
break;
|
||||
}
|
||||
|
||||
if (AL.getKind() == ParsedAttr::AT_NoDeref) {
|
||||
// FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
|
||||
// See https://github.com/llvm/llvm-project/issues/55790 for details.
|
||||
// We allow processTypeAttrs() to emit a warning and silently move on.
|
||||
break;
|
||||
}
|
||||
}
|
||||
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
|
||||
// statement attribute is not written on a declaration, but this code is
|
||||
// needed for attributes in Attr.td that do not list any subjects.
|
||||
S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)
|
||||
// needed for type attributes as well as statement attributes in Attr.td
|
||||
// that do not list any subjects.
|
||||
S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)
|
||||
<< AL << D->getLocation();
|
||||
break;
|
||||
case ParsedAttr::AT_Interrupt:
|
||||
|
@ -9010,14 +9078,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
|
||||
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
|
||||
/// attribute list to the specified decl, ignoring any type attributes.
|
||||
void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
|
||||
const ParsedAttributesView &AttrList,
|
||||
bool IncludeCXX11Attributes) {
|
||||
void Sema::ProcessDeclAttributeList(
|
||||
Scope *S, Decl *D, const ParsedAttributesView &AttrList,
|
||||
const ProcessDeclAttributeOptions &Options) {
|
||||
if (AttrList.empty())
|
||||
return;
|
||||
|
||||
for (const ParsedAttr &AL : AttrList)
|
||||
ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes);
|
||||
ProcessDeclAttribute(*this, S, D, AL, Options);
|
||||
|
||||
// FIXME: We should be able to handle these cases in TableGen.
|
||||
// GCC accepts
|
||||
|
@ -9105,7 +9173,8 @@ bool Sema::ProcessAccessDeclAttributeList(
|
|||
AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
|
||||
for (const ParsedAttr &AL : AttrList) {
|
||||
if (AL.getKind() == ParsedAttr::AT_Annotate) {
|
||||
ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute());
|
||||
ProcessDeclAttribute(*this, nullptr, ASDecl, AL,
|
||||
ProcessDeclAttributeOptions());
|
||||
} else {
|
||||
Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
|
||||
return true;
|
||||
|
@ -9138,6 +9207,7 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) {
|
|||
/// used to build a declaration, complain about any decl attributes
|
||||
/// which might be lying around on it.
|
||||
void Sema::checkUnusedDeclAttributes(Declarator &D) {
|
||||
::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes());
|
||||
::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
|
||||
::checkUnusedDeclAttributes(*this, D.getAttributes());
|
||||
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
|
||||
|
@ -9246,17 +9316,43 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
|
|||
/// it, apply them to D. This is a bit tricky because PD can have attributes
|
||||
/// specified in many different places, and we need to find and apply them all.
|
||||
void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
|
||||
// Ordering of attributes can be important, so we take care to process
|
||||
// attributes in the order in which they appeared in the source code.
|
||||
|
||||
// First, process attributes that appeared on the declaration itself (but
|
||||
// only if they don't have the legacy behavior of "sliding" to the DeclSepc).
|
||||
ParsedAttributesView NonSlidingAttrs;
|
||||
for (ParsedAttr &AL : PD.getDeclarationAttributes()) {
|
||||
if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
|
||||
// Skip processing the attribute, but do check if it appertains to the
|
||||
// declaration. This is needed for the `MatrixType` attribute, which,
|
||||
// despite being a type attribute, defines a `SubjectList` that only
|
||||
// allows it to be used on typedef declarations.
|
||||
AL.diagnoseAppertainsTo(*this, D);
|
||||
} else {
|
||||
NonSlidingAttrs.addAtEnd(&AL);
|
||||
}
|
||||
}
|
||||
ProcessDeclAttributeList(S, D, NonSlidingAttrs);
|
||||
|
||||
// Apply decl attributes from the DeclSpec if present.
|
||||
if (!PD.getDeclSpec().getAttributes().empty())
|
||||
ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes());
|
||||
if (!PD.getDeclSpec().getAttributes().empty()) {
|
||||
ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes(),
|
||||
ProcessDeclAttributeOptions()
|
||||
.WithIncludeCXX11Attributes(false)
|
||||
.WithIgnoreTypeAttributes(true));
|
||||
}
|
||||
|
||||
// Walk the declarator structure, applying decl attributes that were in a type
|
||||
// position to the decl itself. This handles cases like:
|
||||
// int *__attr__(x)** D;
|
||||
// when X is a decl attribute.
|
||||
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
|
||||
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) {
|
||||
ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(),
|
||||
/*IncludeCXX11Attributes=*/false);
|
||||
ProcessDeclAttributeOptions()
|
||||
.WithIncludeCXX11Attributes(false)
|
||||
.WithIgnoreTypeAttributes(true));
|
||||
}
|
||||
|
||||
// Finally, apply any attributes on the decl itself.
|
||||
ProcessDeclAttributeList(S, D, PD.getAttributes());
|
||||
|
|
|
@ -16860,7 +16860,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
|
|||
// Try to convert the decl specifier to a type. This works for
|
||||
// friend templates because ActOnTag never produces a ClassTemplateDecl
|
||||
// for a TUK_Friend.
|
||||
Declarator TheDeclarator(DS, DeclaratorContext::Member);
|
||||
Declarator TheDeclarator(DS, ParsedAttributesView::none(),
|
||||
DeclaratorContext::Member);
|
||||
TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S);
|
||||
QualType T = TSI->getType();
|
||||
if (TheDeclarator.isInvalidType())
|
||||
|
|
|
@ -1588,7 +1588,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
|
|||
DS.SetRangeEnd(loc);
|
||||
|
||||
// Form the declarator.
|
||||
Declarator D(DS, DeclaratorContext::TypeName);
|
||||
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName);
|
||||
|
||||
// If we have a typedef of an Objective-C class type that is missing a '*',
|
||||
// add the '*'.
|
||||
|
|
|
@ -629,15 +629,6 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
|
|||
QualType &declSpecType) {
|
||||
state.saveDeclSpecAttrs();
|
||||
|
||||
// C++11 attributes before the decl specifiers actually appertain to
|
||||
// the declarators. Move them straight there. We don't support the
|
||||
// 'put them wherever you like' semantics we allow for GNU attributes.
|
||||
if (attr.isStandardAttributeSyntax()) {
|
||||
moveAttrFromListToList(attr, state.getCurrentAttributes(),
|
||||
state.getDeclarator().getAttributes());
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to distribute to the innermost.
|
||||
if (distributeFunctionTypeAttrToInnermost(
|
||||
state, attr, state.getCurrentAttributes(), declSpecType))
|
||||
|
@ -648,8 +639,10 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
|
|||
state.addIgnoredTypeAttr(attr);
|
||||
}
|
||||
|
||||
/// A function type attribute was written on the declarator. Try to
|
||||
/// apply it somewhere.
|
||||
/// A function type attribute was written on the declarator or declaration.
|
||||
/// Try to apply it somewhere.
|
||||
/// `Attrs` is the attribute list containing the declaration (either of the
|
||||
/// declarator or the declaration).
|
||||
static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
|
||||
ParsedAttr &attr,
|
||||
QualType &declSpecType) {
|
||||
|
@ -666,7 +659,7 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
|
|||
state.addIgnoredTypeAttr(attr);
|
||||
}
|
||||
|
||||
/// Given that there are attributes written on the declarator
|
||||
/// Given that there are attributes written on the declarator or declaration
|
||||
/// itself, try to distribute any type attributes to the appropriate
|
||||
/// declarator chunk.
|
||||
///
|
||||
|
@ -675,11 +668,11 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
|
|||
/// int (f ATTR)();
|
||||
/// but not necessarily this:
|
||||
/// int f() ATTR;
|
||||
///
|
||||
/// `Attrs` is the attribute list containing the declaration (either of the
|
||||
/// declarator or the declaration).
|
||||
static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
|
||||
QualType &declSpecType) {
|
||||
// Collect all the type attributes from the declarator itself.
|
||||
assert(!state.getDeclarator().getAttributes().empty() &&
|
||||
"declarator has no attrs!");
|
||||
// The called functions in this loop actually remove things from the current
|
||||
// list, so iterating over the existing list isn't possible. Instead, make a
|
||||
// non-owning copy and iterate over that.
|
||||
|
@ -1792,8 +1785,42 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
|||
// list of type attributes to be temporarily saved while the type
|
||||
// attributes are pushed around.
|
||||
// pipe attributes will be handled later ( at GetFullTypeForDeclarator )
|
||||
if (!DS.isTypeSpecPipe())
|
||||
if (!DS.isTypeSpecPipe()) {
|
||||
// We also apply declaration attributes that "slide" to the decl spec.
|
||||
// Ordering can be important for attributes. The decalaration attributes
|
||||
// come syntactically before the decl spec attributes, so we process them
|
||||
// in that order.
|
||||
ParsedAttributesView SlidingAttrs;
|
||||
for (ParsedAttr &AL : declarator.getDeclarationAttributes()) {
|
||||
if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
|
||||
SlidingAttrs.addAtEnd(&AL);
|
||||
|
||||
// For standard syntax attributes, which would normally appertain to the
|
||||
// declaration here, suggest moving them to the type instead. But only
|
||||
// do this for our own vendor attributes; moving other vendors'
|
||||
// attributes might hurt portability.
|
||||
// There's one special case that we need to deal with here: The
|
||||
// `MatrixType` attribute may only be used in a typedef declaration. If
|
||||
// it's being used anywhere else, don't output the warning as
|
||||
// ProcessDeclAttributes() will output an error anyway.
|
||||
if (AL.isStandardAttributeSyntax() && AL.isClangScope() &&
|
||||
!(AL.getKind() == ParsedAttr::AT_MatrixType &&
|
||||
DS.getStorageClassSpec() != DeclSpec::SCS_typedef)) {
|
||||
S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
|
||||
<< AL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// During this call to processTypeAttrs(),
|
||||
// TypeProcessingState::getCurrentAttributes() will erroneously return a
|
||||
// reference to the DeclSpec attributes, rather than the declaration
|
||||
// attributes. However, this doesn't matter, as getCurrentAttributes()
|
||||
// is only called when distributing attributes from one attribute list
|
||||
// to another. Declaration attributes are always C++11 attributes, and these
|
||||
// are never distributed.
|
||||
processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs);
|
||||
processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes());
|
||||
}
|
||||
|
||||
// Apply const/volatile/restrict qualifiers to T.
|
||||
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
|
||||
|
@ -3400,7 +3427,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!D.getAttributes().empty())
|
||||
// Note: We don't need to distribute declaration attributes (i.e.
|
||||
// D.getDeclarationAttributes()) because those are always C++11 attributes,
|
||||
// and those don't get distributed.
|
||||
distributeTypeAttrsFromDeclarator(state, T);
|
||||
|
||||
// Find the deduced type in this type. Look in the trailing return type if we
|
||||
|
@ -4702,7 +4731,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
AttrList.hasAttribute(ParsedAttr::AT_CFReturnsNotRetained);
|
||||
};
|
||||
if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) {
|
||||
if (hasCFReturnsAttr(D.getAttributes()) ||
|
||||
if (hasCFReturnsAttr(D.getDeclarationAttributes()) ||
|
||||
hasCFReturnsAttr(D.getAttributes()) ||
|
||||
hasCFReturnsAttr(InnermostChunk->getAttrs()) ||
|
||||
hasCFReturnsAttr(D.getDeclSpec().getAttributes())) {
|
||||
inferNullability = NullabilityKind::Nullable;
|
||||
|
@ -5273,7 +5303,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
// function is marked with the "overloadable" attribute. Scan
|
||||
// for this attribute now.
|
||||
if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus)
|
||||
if (!D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
|
||||
if (!D.getDeclarationAttributes().hasAttribute(
|
||||
ParsedAttr::AT_Overloadable) &&
|
||||
!D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
|
||||
!D.getDeclSpec().getAttributes().hasAttribute(
|
||||
ParsedAttr::AT_Overloadable))
|
||||
S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param);
|
||||
|
@ -5689,7 +5721,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
}
|
||||
}
|
||||
|
||||
// Apply any undistributed attributes from the declarator.
|
||||
// Apply any undistributed attributes from the declaration or declarator.
|
||||
ParsedAttributesView NonSlidingAttrs;
|
||||
for (ParsedAttr &AL : D.getDeclarationAttributes()) {
|
||||
if (!AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
|
||||
NonSlidingAttrs.addAtEnd(&AL);
|
||||
}
|
||||
}
|
||||
processTypeAttrs(state, T, TAL_DeclName, NonSlidingAttrs);
|
||||
processTypeAttrs(state, T, TAL_DeclName, D.getAttributes());
|
||||
|
||||
// Diagnose any ignored type attributes.
|
||||
|
@ -8234,12 +8273,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
|||
if (!IsTypeAttr)
|
||||
continue;
|
||||
}
|
||||
} else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr) &&
|
||||
attr.getKind() != ParsedAttr::AT_AnnotateType) {
|
||||
} else if (TAL != TAL_DeclSpec && TAL != TAL_DeclChunk &&
|
||||
!attr.isTypeAttr()) {
|
||||
// Otherwise, only consider type processing for a C++11 attribute if
|
||||
// it's actually been applied to a type.
|
||||
// We also allow C++11 address_space and annotate_type and
|
||||
// OpenCL language address space attributes to pass through.
|
||||
// - it has actually been applied to a type (decl-specifier-seq or
|
||||
// declarator chunk), or
|
||||
// - it is a type attribute, irrespective of where it was applied (so
|
||||
// that we can support the legacy behavior of some type attributes
|
||||
// that can be applied to the declaration name).
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -8257,10 +8298,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
|||
break;
|
||||
|
||||
case ParsedAttr::UnknownAttribute:
|
||||
if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk)
|
||||
if (attr.isStandardAttributeSyntax()) {
|
||||
state.getSema().Diag(attr.getLoc(),
|
||||
diag::warn_unknown_attribute_ignored)
|
||||
<< attr << attr.getRange();
|
||||
// Mark the attribute as invalid so we don't emit the same diagnostic
|
||||
// multiple times.
|
||||
attr.setInvalid();
|
||||
}
|
||||
break;
|
||||
|
||||
case ParsedAttr::IgnoredAttribute:
|
||||
|
@ -8329,6 +8374,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
|||
break;
|
||||
|
||||
case ParsedAttr::AT_NoDeref: {
|
||||
// FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
|
||||
// See https://github.com/llvm/llvm-project/issues/55790 for details.
|
||||
// For the time being, we simply emit a warning that the attribute is
|
||||
// ignored.
|
||||
if (attr.isStandardAttributeSyntax()) {
|
||||
state.getSema().Diag(attr.getLoc(), diag::warn_attribute_ignored)
|
||||
<< attr;
|
||||
break;
|
||||
}
|
||||
ASTContext &Ctx = state.getSema().Context;
|
||||
type = state.getAttributedType(createSimpleAttr<NoDerefAttr>(Ctx, attr),
|
||||
type, type);
|
||||
|
@ -8406,6 +8460,16 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
|||
FUNCTION_TYPE_ATTRS_CASELIST:
|
||||
attr.setUsedAsTypeAttr();
|
||||
|
||||
// Attributes with standard syntax have strict rules for what they
|
||||
// appertain to and hence should not use the "distribution" logic below.
|
||||
if (attr.isStandardAttributeSyntax()) {
|
||||
if (!handleFunctionTypeAttr(state, attr, type)) {
|
||||
diagnoseBadTypeAttribute(state.getSema(), attr, type);
|
||||
attr.setInvalid();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Never process function type attributes as part of the
|
||||
// declaration-specifiers.
|
||||
if (TAL == TAL_DeclSpec)
|
||||
|
|
|
@ -14,42 +14,63 @@ void langas() {
|
|||
// CHECK: VarDecl {{.*}} x_global '__global int *'
|
||||
__attribute__((opencl_global)) int *x_global;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_global '__global int *'
|
||||
int [[clang::opencl_global]] *y_global;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_global '__global int *'
|
||||
[[clang::opencl_global]] int *z_global;
|
||||
|
||||
// CHECK: VarDecl {{.*}} x_global_device '__global_device int *'
|
||||
__attribute__((opencl_global_device)) int *x_global_device;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_global_device '__global_device int *'
|
||||
int [[clang::opencl_global_device]] *y_global_device;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_global_device '__global_device int *'
|
||||
[[clang::opencl_global_device]] int *z_global_device;
|
||||
|
||||
// CHECK: VarDecl {{.*}} x_global_host '__global_host int *'
|
||||
__attribute__((opencl_global_host)) int *x_global_host;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_global_host '__global_host int *'
|
||||
int [[clang::opencl_global_host]] *y_global_host;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_global_host '__global_host int *'
|
||||
[[clang::opencl_global_host]] int *z_global_host;
|
||||
|
||||
// CHECK: VarDecl {{.*}} x_local '__local int *'
|
||||
__attribute__((opencl_local)) int *x_local;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_local '__local int *'
|
||||
int [[clang::opencl_local]] *y_local;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_local '__local int *'
|
||||
[[clang::opencl_local]] int *z_local;
|
||||
|
||||
// CHECK: VarDecl {{.*}} x_constant '__constant int *'
|
||||
__attribute__((opencl_constant)) int *x_constant;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_constant '__constant int *'
|
||||
int [[clang::opencl_constant]] *y_constant;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_constant '__constant int *'
|
||||
[[clang::opencl_constant]] int *z_constant;
|
||||
|
||||
// CHECK: VarDecl {{.*}} x_private '__private int *'
|
||||
__attribute__((opencl_private)) int *x_private;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_private '__private int *'
|
||||
int [[clang::opencl_private]] *y_private;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_private '__private int *'
|
||||
[[clang::opencl_private]] int *z_private;
|
||||
|
||||
// CHECK: VarDecl {{.*}} x_generic '__generic int *'
|
||||
__attribute__((opencl_generic)) int *x_generic;
|
||||
|
||||
// CHECK: VarDecl {{.*}} y_generic '__generic int *'
|
||||
int [[clang::opencl_generic]] *y_generic;
|
||||
|
||||
// CHECK: VarDecl {{.*}} z_generic '__generic int *'
|
||||
[[clang::opencl_generic]] int *z_generic;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -fdouble-square-bracket-attributes -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
#if DOUBLE_BRACKET_ATTRS
|
||||
#define __tag1 [[clang::btf_type_tag("tag1")]]
|
||||
#define __tag2 [[clang::btf_type_tag("tag2")]]
|
||||
#define __tag3 [[clang::btf_type_tag("tag3")]]
|
||||
#define __tag4 [[clang::btf_type_tag("tag4")]]
|
||||
#else
|
||||
#define __tag1 __attribute__((btf_type_tag("tag1")))
|
||||
#define __tag2 __attribute__((btf_type_tag("tag2")))
|
||||
#define __tag3 __attribute__((btf_type_tag("tag3")))
|
||||
#define __tag4 __attribute__((btf_type_tag("tag4")))
|
||||
#endif
|
||||
|
||||
int __tag1 * __tag2 *foo(int __tag1 * __tag2 *arg) { return arg; }
|
||||
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
// RUN: %clang_cc1 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -DDOUBLE_BRACKET_ATTRS=1 -fdouble-square-bracket-attributes -debug-info-kind=limited -S -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
#if DOUBLE_BRACKET_ATTRS
|
||||
#define __tag1 [[clang::btf_type_tag("tag1")]]
|
||||
#define __tag2 [[clang::btf_type_tag("tag2")]]
|
||||
#define __tag3 [[clang::btf_type_tag("tag3")]]
|
||||
#define __tag4 [[clang::btf_type_tag("tag4")]]
|
||||
#define __tag5 [[clang::btf_type_tag("tag5")]]
|
||||
#define __tag6 [[clang::btf_type_tag("tag6")]]
|
||||
|
||||
const volatile int __tag1 __tag2 * __tag3 __tag4 const volatile * __tag5 __tag6 const volatile * g;
|
||||
#else
|
||||
#define __tag1 __attribute__((btf_type_tag("tag1")))
|
||||
#define __tag2 __attribute__((btf_type_tag("tag2")))
|
||||
#define __tag3 __attribute__((btf_type_tag("tag3")))
|
||||
|
@ -8,6 +19,7 @@
|
|||
#define __tag6 __attribute__((btf_type_tag("tag6")))
|
||||
|
||||
const int __tag1 __tag2 volatile * const __tag3 __tag4 volatile * __tag5 __tag6 const volatile * g;
|
||||
#endif
|
||||
|
||||
// CHECK: distinct !DIGlobalVariable(name: "g", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[L6:[0-9]+]]
|
||||
// CHECK: ![[L6]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[L7:[0-9]+]], size: [[#]], annotations: ![[L22:[0-9]+]]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -Wno-unused-value -verify %s
|
||||
// RUN: %clang_cc1 -Wno-unused-value -fdouble-square-bracket-attributes -verify %s
|
||||
|
||||
#define NODEREF __attribute__((noderef))
|
||||
|
||||
|
@ -221,3 +221,24 @@ int test(void) {
|
|||
do {} while (*p); // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
|
||||
return *p; // expected-warning{{dereferencing p; was declared with a 'noderef' type}}
|
||||
}
|
||||
|
||||
// FIXME: Currently, [[]] syntax does not work for the `noderef` atribute.
|
||||
// For the time being, test that we consistently diagnose the attribute as
|
||||
// ignored.
|
||||
// For details see https://github.com/llvm/llvm-project/issues/55790
|
||||
void test_standard_syntax() {
|
||||
[[clang::noderef]] int i; // expected-warning {{'noderef' attribute ignored}}
|
||||
|
||||
[[clang::noderef]] int *p1; // expected-warning {{'noderef' attribute ignored}}
|
||||
*p1;
|
||||
|
||||
int *p2 [[clang::noderef]]; // expected-warning {{'noderef' attribute ignored}}
|
||||
*p2;
|
||||
|
||||
int * [[clang::noderef]] p3; // expected-warning {{'noderef' attribute ignored}}
|
||||
*p3;
|
||||
|
||||
typedef int* IntPtr;
|
||||
[[clang::noderef]] IntPtr p4; // expected-warning {{'noderef' attribute ignored}}
|
||||
*p4;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,14 @@ struct __declspec(uuid("000000A0-0000-0000-C000-000000000046"))
|
|||
struct_with_uuid { };
|
||||
struct struct_without_uuid { };
|
||||
|
||||
struct base {
|
||||
int a;
|
||||
};
|
||||
struct derived : base {
|
||||
// Can't apply a UUID to a using declaration.
|
||||
[uuid("000000A0-0000-0000-C000-00000000004A")] using base::a; // expected-error {{expected member name}}
|
||||
};
|
||||
|
||||
struct __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
|
||||
struct_with_uuid2;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
|
||||
|
||||
#if !__has_extension(gnu_asm)
|
||||
#error Extension 'gnu_asm' should be available by default
|
||||
|
@ -12,6 +12,9 @@ void f1(void) {
|
|||
void f2(void) {
|
||||
asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}}
|
||||
asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}}
|
||||
|
||||
[[]] asm("");
|
||||
[[gnu::deprecated]] asm(""); // expected-warning {{'deprecated' attribute ignored}}
|
||||
}
|
||||
|
||||
void a(void) __asm__(""); // expected-error {{cannot use an empty string literal in 'asm'}}
|
||||
|
|
|
@ -7,3 +7,8 @@ int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in
|
|||
int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
|
||||
int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
|
||||
int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}}
|
||||
|
||||
void f() {
|
||||
[[]] asm("");
|
||||
[[gnu::deprecated]] asm(""); // expected-warning {{'deprecated' attribute ignored}}
|
||||
}
|
||||
|
|
|
@ -113,3 +113,10 @@ __attribute__((,,,const)) int PR38352_1(void);
|
|||
__attribute__((const,,,)) int PR38352_2(void);
|
||||
__attribute__((const,,,const)) int PR38352_3(void);
|
||||
__attribute__((,,,const,,,const,,,)) int PR38352_4(void);
|
||||
|
||||
// Test that we allow attributes on free-standing decl-specifier-seqs.
|
||||
// GCC appears to allow this.
|
||||
__attribute__(()) struct t;
|
||||
void f5() {
|
||||
__attribute__(()) struct t;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ struct [[]] S1 {
|
|||
int [[]] : 0; // OK, attribute applies to the type.
|
||||
int p, [[]] : 0; // expected-error {{an attribute list cannot appear here}}
|
||||
int q, [[]] r; // expected-error {{an attribute list cannot appear here}}
|
||||
[[]] int; // expected-error {{an attribute list cannot appear here}} \
|
||||
// expected-warning {{declaration does not declare anything}}
|
||||
};
|
||||
|
||||
[[]] struct S2 { int a; }; // expected-error {{misplaced attributes}}
|
||||
|
|
|
@ -126,6 +126,7 @@ class foo {
|
|||
void const_after_attr () [[]] const; // expected-error {{expected ';'}}
|
||||
};
|
||||
extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
|
||||
[[]] extern "C++" { } // expected-error {{an attribute list cannot appear here}}
|
||||
[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
|
||||
[[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}} expected-note {{declared here}}
|
||||
[[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}}
|
||||
|
@ -421,3 +422,26 @@ class FriendClassesWithAttributes {
|
|||
// prefered "protected" vendor namespace. We support __clang__ only for
|
||||
// people expecting it to behave the same as __gnu__.
|
||||
[[__clang__::annotate("test")]] void annotate3(); // expected-warning {{'__clang__' is a predefined macro name, not an attribute scope specifier; did you mean '_Clang' instead?}}
|
||||
|
||||
// Check ordering: C++11 attributes must appear before GNU attributes.
|
||||
class Ordering {
|
||||
void f1(
|
||||
int ([[]] __attribute__(()) int n)
|
||||
) {
|
||||
}
|
||||
|
||||
void f2(
|
||||
int (*)([[]] __attribute__(()) int n)
|
||||
) {
|
||||
}
|
||||
|
||||
void f3(
|
||||
int (__attribute__(()) [[]] int n) // expected-error {{an attribute list cannot appear here}}
|
||||
) {
|
||||
}
|
||||
|
||||
void f4(
|
||||
int (*)(__attribute__(()) [[]] int n) // expected-error {{an attribute list cannot appear here}}
|
||||
) {
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,11 +17,8 @@ void foo(float *[[clang::annotate_type("foo")]] a) {
|
|||
int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}}
|
||||
|
||||
// Various error cases
|
||||
// FIXME: We would want to prohibit the attribute on the following two lines.
|
||||
// However, Clang currently generally doesn't prohibit type-only C++11
|
||||
// attributes on declarations. This should be fixed more generally.
|
||||
[[clang::annotate_type("bar")]] int *z1;
|
||||
int *z2 [[clang::annotate_type("bar")]];
|
||||
[[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
[[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}}
|
||||
int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}}
|
||||
int *[[clang::annotate_type()]] z4; // expected-error {{'annotate_type' attribute takes at least 1 argument}}
|
||||
|
@ -33,15 +30,13 @@ void foo(float *[[clang::annotate_type("foo")]] a) {
|
|||
}
|
||||
// More error cases: Prohibit adding the attribute to declarations.
|
||||
// Different declarations hit different code paths, so they need separate tests.
|
||||
// FIXME: Clang currently generally doesn't prohibit type-only C++11
|
||||
// attributes on declarations.
|
||||
[[clang::annotate_type("bar")]] int *global;
|
||||
void annotated_function([[clang::annotate_type("bar")]] int);
|
||||
void g([[clang::annotate_type("bar")]] int);
|
||||
struct [[clang::annotate_type("foo")]] S;
|
||||
struct [[clang::annotate_type("foo")]] S{
|
||||
[[clang::annotate_type("foo")]] int member;
|
||||
[[clang::annotate_type("foo")]] union {
|
||||
[[clang::annotate_type("bar")]] int *global; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
[[clang::annotate_type("bar")]] void annotated_function(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
void g([[clang::annotate_type("bar")]] int); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
struct [[clang::annotate_type("foo")]] S; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
struct [[clang::annotate_type("foo")]] S{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
[[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
[[clang::annotate_type("foo")]] union { // expected-error {{an attribute list cannot appear here}}
|
||||
int i;
|
||||
float f;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,16 @@ __attribute__((visibility("hidden"))) __attribute__((aligned)) union B; // expe
|
|||
__attribute__((visibility("hidden"))) __attribute__((aligned)) enum C {C}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
|
||||
// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
|
||||
|
||||
// Make sure that we produce the same warnings on block declarations.
|
||||
void func() {
|
||||
__attribute__((visibility("hidden"))) __attribute__((aligned)) struct A; // expected-warning{{attribute 'visibility' is ignored, place it after "struct" to apply attribute to type declaration}} \
|
||||
// expected-warning{{attribute 'aligned' is ignored, place it after "struct" to apply attribute to type declaration}}
|
||||
__attribute__((visibility("hidden"))) __attribute__((aligned)) union B; // expected-warning{{attribute 'visibility' is ignored, place it after "union" to apply attribute to type declaration}} \
|
||||
// expected-warning{{attribute 'aligned' is ignored, place it after "union" to apply attribute to type declaration}}
|
||||
__attribute__((visibility("hidden"))) __attribute__((aligned)) enum C {C}; // expected-warning{{attribute 'visibility' is ignored, place it after "enum" to apply attribute to type declaration}} \
|
||||
// expected-warning{{attribute 'aligned' is ignored, place it after "enum" to apply attribute to type declaration}}
|
||||
}
|
||||
|
||||
__attribute__((visibility("hidden"))) __attribute__((aligned)) struct D {} d;
|
||||
__attribute__((visibility("hidden"))) __attribute__((aligned)) union E {} e;
|
||||
__attribute__((visibility("hidden"))) __attribute__((aligned)) enum F {F} f;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
|
||||
|
||||
__attribute((regparm(2))) int x0(void);
|
||||
__attribute((regparm(1.0))) int x1(void); // expected-error{{'regparm' attribute requires an integer constant}}
|
||||
|
@ -9,3 +9,9 @@ __attribute((regparm(5,3))) int x4(void); // expected-error{{'regparm' attribute
|
|||
void __attribute__((regparm(3))) x5(int);
|
||||
void x5(int); // expected-note{{previous declaration is here}}
|
||||
void __attribute__((regparm(2))) x5(int); // expected-error{{function declared with regparm(2) attribute was previously declared with the regparm(3) attribute}}
|
||||
|
||||
[[gnu::regparm(3)]] void x6(int); // expected-note{{previous declaration is here}}
|
||||
[[gnu::regparm(2)]] void x6(int); // expected-error{{function declared with regparm(2) attribute was previously declared with the regparm(3) attribute}}
|
||||
void x6 [[gnu::regparm(3)]] (int);
|
||||
void [[gnu::regparm(3)]] x6(int); // expected-warning{{'regparm' only applies to function types; type here is 'void'}}
|
||||
void x6(int) [[gnu::regparm(3)]]; // expected-warning{{GCC does not allow the 'regparm' attribute to be written on a type}}
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
// RUN: %clang_cc1 %s -fenable-matrix -pedantic -verify -triple=x86_64-apple-darwin9
|
||||
// RUN: %clang_cc1 %s -fenable-matrix -fdouble-square-bracket-attributes -pedantic -verify -triple=x86_64-apple-darwin9
|
||||
|
||||
typedef float sx5x10_t __attribute__((matrix_type(5, 10)));
|
||||
typedef int ix3x2_t __attribute__((matrix_type(3, 2)));
|
||||
typedef double dx3x3 __attribute__((matrix_type(3, 3)));
|
||||
typedef unsigned ix3x3 __attribute__((matrix_type(3, 3)));
|
||||
|
||||
// Verify that we can use the [[]] spelling of the attribute.
|
||||
// We intentionally use the same type alias name to check that both versions
|
||||
// define the same type.
|
||||
typedef float [[clang::matrix_type(5, 10)]] sx5x10_t;
|
||||
typedef int [[clang::matrix_type(3, 2)]] ix3x2_t;
|
||||
[[clang::matrix_type(5, 10)]] typedef float sx5x10_t;
|
||||
// expected-warning@-1 {{applying attribute 'matrix_type' to a declaration is deprecated; apply it to the type instead}}
|
||||
[[clang::matrix_type(3, 2)]] typedef int ix3x2_t;
|
||||
// expected-warning@-1 {{applying attribute 'matrix_type' to a declaration is deprecated; apply it to the type instead}}
|
||||
|
||||
// Attribute may not be used outside typedefs.
|
||||
[[clang::matrix_type(3, 2)]] int ix3x2_var;
|
||||
// expected-error@-1 {{'matrix_type' attribute only applies to typedefs}}
|
||||
int [[clang::matrix_type(3, 2)]] ix3x2_var;
|
||||
// expected-error@-1 {{'matrix_type' attribute only applies to typedefs}}
|
||||
|
||||
void transpose(sx5x10_t a, ix3x2_t b, dx3x3 c, int *d, int e) {
|
||||
a = __builtin_matrix_transpose(b);
|
||||
// expected-error@-1 {{assigning to 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') from incompatible type 'int __attribute__((matrix_type(2, 3)))'}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 %s -triple armv7 -target-feature +neon -fsyntax-only -verify
|
||||
// RUN: %clang_cc1 %s -triple armv8 -target-feature +neon -fsyntax-only -verify
|
||||
// RUN: %clang_cc1 %s -triple armv7 -target-feature +neon -fsyntax-only -fdouble-square-bracket-attributes -verify
|
||||
// RUN: %clang_cc1 %s -triple armv8 -target-feature +neon -fsyntax-only -fdouble-square-bracket-attributes -verify
|
||||
|
||||
typedef float float32_t;
|
||||
typedef signed char poly8_t;
|
||||
|
@ -16,6 +16,16 @@ typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t;
|
|||
typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
|
||||
typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t;
|
||||
|
||||
// Verify that we can use the [[]] spelling of the attributes.
|
||||
// We intentionally use the same type alias names to check that both versions
|
||||
// define the same type.
|
||||
typedef int [[clang::neon_vector_type(2)]] int32x2_t;
|
||||
typedef poly8_t [[clang::neon_polyvector_type(16)]] poly8x16_t;
|
||||
|
||||
// Verify that we can use the attributes outside of a typedef.
|
||||
int [[clang::neon_vector_type(2)]] int32x2_var;
|
||||
poly8_t [[clang::neon_polyvector_type(16)]] poly8x16_var;
|
||||
|
||||
// The attributes must have a single argument.
|
||||
typedef __attribute__((neon_vector_type(2, 4))) int only_one_arg; // expected-error{{'neon_vector_type' attribute takes one argument}}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -Werror -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -verify -fsyntax-only -DERROR_CHECK %s
|
||||
// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -fdouble-square-bracket-attributes -Werror -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -flax-vector-conversions=all -fdouble-square-bracket-attributes -verify -fsyntax-only -DERROR_CHECK %s
|
||||
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
|
@ -15,6 +15,14 @@ typedef __attribute__((neon_vector_type(8), __clang_arm_mve_strict_polymorphism)
|
|||
typedef __attribute__((neon_vector_type(4), __clang_arm_mve_strict_polymorphism)) uint32_t uint32x4_t;
|
||||
typedef __attribute__((neon_vector_type(2), __clang_arm_mve_strict_polymorphism)) uint64_t uint64x2_t;
|
||||
|
||||
// Verify that we can use the [[]] spelling of the attribute.
|
||||
// We intentionally use the same type alias name to check that both versions
|
||||
// define the same type.
|
||||
typedef int16_t [[clang::neon_vector_type(8), clang::__clang_arm_mve_strict_polymorphism]] int16x8_t;
|
||||
|
||||
// Verify that we can use the attribute outside of a typedef.
|
||||
void test_param(int16_t [[clang::neon_vector_type(8), clang::__clang_arm_mve_strict_polymorphism]] int16x8);
|
||||
|
||||
__attribute__((overloadable))
|
||||
int overload(int16x8_t x, int16_t y); // expected-note {{candidate function}}
|
||||
__attribute__((overloadable))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 %s -verify -fsyntax-only -Weverything -Wno-unused-but-set-variable -triple x86_64-apple-darwin10
|
||||
// RUN: %clang_cc1 %s -verify -fsyntax-only -fdouble-square-bracket-attributes -Weverything -Wno-unused-but-set-variable -triple x86_64-apple-darwin10
|
||||
|
||||
// Test the compatibility of clang's vector extensions with gcc's vector
|
||||
// extensions for C. Notably &&, ||, ?: and ! are not available.
|
||||
|
@ -17,6 +17,32 @@ typedef double v2f64 __attribute__((vector_size(16)));
|
|||
typedef double v4f64 __attribute__((vector_size(32)));
|
||||
typedef int v4i32 __attribute((vector_size(16)));
|
||||
|
||||
// Verify that we can use the [[]] spelling of the attribute.
|
||||
// We intentionally use the same type alias name to check that both versions
|
||||
// define the same type.
|
||||
// FIXME: Warnings are nuisance warnings due to the `-Weverything` flag, but
|
||||
// we shouldn't really be emitting them in C mode with the
|
||||
// `-fdouble-square-bracket-attributes` flag.
|
||||
typedef long long v2i64 [[gnu::vector_size(16)]]; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
|
||||
typedef int v2i32 [[gnu::vector_size(8)]]; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
|
||||
|
||||
// Check various positions where the [[]] spelling can or cannot be used.
|
||||
[[gnu::vector_size(16)]] typedef long long v2i64; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
|
||||
typedef long long [[gnu::vector_size(16)]] v2i64_ignored;
|
||||
// expected-warning@-1{{'vector_size' attribute ignored}}
|
||||
// expected-warning@-2{{C++11 attribute syntax is incompatible with C++98}}
|
||||
// FIXME: Contrary to the error message that we emit, GCC does actually allow
|
||||
// the attribute in the following position. Somewhat surprisingly, the attribute
|
||||
// is applied not to the pointer but to the base type, i.e. this declaration has
|
||||
// the same effect in GCC as the other declarations for `v2i64`.
|
||||
typedef long long *[[gnu::vector_size(16)]] v2i64_doesnt_work;
|
||||
// expected-error@-1{{invalid vector element type 'long long *'}}
|
||||
// expected-warning@-2{{GCC does not allow the 'vector_size' attribute to be written on a type}}
|
||||
// expected-warning@-3{{C++11 attribute syntax is incompatible with C++98}}
|
||||
|
||||
// Verify that we can use the attribute outside of a typedef.
|
||||
static int v2i32_var [[gnu::vector_size(8)]]; // expected-warning{{C++11 attribute syntax is incompatible with C++98}}
|
||||
|
||||
void arithmeticTest(void);
|
||||
void logicTest(void);
|
||||
void comparisonTest(void);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s
|
||||
|
||||
// Check that we emit the correct warnings in various situations where the C++11
|
||||
// spelling of the `address_space` attribute is applied to a declaration instead
|
||||
// of a type. Also check that the attribute can instead be applied to the type.
|
||||
|
||||
void f([[clang::address_space(1)]] int* param) { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
[[clang::address_space(1)]] int* local1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
int* local2 [[clang::address_space(1)]]; // expected-error {{automatic variable qualified with an address space}} expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
int [[clang::address_space(1)]] * local3;
|
||||
int* [[clang::address_space(1)]] local4; // expected-error {{automatic variable qualified with an address space}}
|
||||
|
||||
for ([[clang::address_space(1)]] int* p = nullptr; p; ++p) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
for (; [[clang::address_space(1)]] int* p = nullptr; ) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
while([[clang::address_space(1)]] int* p = nullptr) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
if ([[clang::address_space(1)]] int* p = nullptr) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
try {
|
||||
} catch([[clang::address_space(1)]] int& i) { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
}
|
||||
|
||||
for (int [[clang::address_space(1)]] * p = nullptr; p; ++p) {}
|
||||
for (; int [[clang::address_space(1)]] * p = nullptr; ) {}
|
||||
while(int [[clang::address_space(1)]] * p = nullptr) {}
|
||||
if (int [[clang::address_space(1)]] * p = nullptr) {}
|
||||
try {
|
||||
} catch(int [[clang::address_space(1)]] & i) {
|
||||
}
|
||||
}
|
||||
|
||||
[[clang::address_space(1)]] int* return_value(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
int [[clang::address_space(1)]] * return_value();
|
||||
|
||||
[[clang::address_space(1)]] int global1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
int global2 [[clang::address_space(1)]]; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
int [[clang::address_space(1)]] global3;
|
||||
int [[clang::address_space(1)]] global4;
|
||||
|
||||
struct [[clang::address_space(1)]] S { // expected-error {{'address_space' attribute cannot be applied to a declaration}}
|
||||
[[clang::address_space(1)]] int* member_function_1(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
int [[clang::address_space(1)]] * member_function_2();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
[[clang::address_space(1)]] T var_template_1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
template <class T>
|
||||
T [[clang::address_space(1)]] var_template_2;
|
||||
|
||||
using void_ptr [[clang::address_space(1)]] = void *; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
|
||||
// Intentionally using the same alias name to check that the aliases define the
|
||||
// same type.
|
||||
using void_ptr = void [[clang::address_space(1)]] *;
|
||||
|
||||
namespace N {}
|
||||
[[clang::address_space(1)]] using namespace N; // expected-error {{'address_space' attribute cannot be applied to a declaration}}
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
struct S1 {
|
||||
void f() [[clang::annotate_type("foo")]];
|
||||
// FIXME: We would want to prohibit the attribute in the following location.
|
||||
// However, Clang currently generally doesn't prohibit type-only C++11
|
||||
// attributes on declarations. This should be fixed more generally.
|
||||
[[clang::annotate_type("foo")]] void g();
|
||||
[[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2> struct is_same {
|
||||
|
@ -48,23 +45,21 @@ void f3() {
|
|||
|
||||
// More error cases: Prohibit adding the attribute to declarations.
|
||||
// Different declarations hit different code paths, so they need separate tests.
|
||||
// FIXME: Clang currently generally doesn't prohibit type-only C++11
|
||||
// attributes on declarations.
|
||||
namespace [[clang::annotate_type("foo")]] my_namespace {}
|
||||
struct [[clang::annotate_type("foo")]] S3;
|
||||
struct [[clang::annotate_type("foo")]] S3{
|
||||
[[clang::annotate_type("foo")]] int member;
|
||||
namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
struct [[clang::annotate_type("foo")]] S3; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
struct [[clang::annotate_type("foo")]] S3{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
[[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
};
|
||||
void f4() {
|
||||
for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {}
|
||||
for (; [[clang::annotate_type("foo")]] bool b = false;) {}
|
||||
while ([[clang::annotate_type("foo")]] bool b = false) {}
|
||||
if ([[clang::annotate_type("foo")]] bool b = false) {}
|
||||
for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
for (; [[clang::annotate_type("foo")]] bool b = false;) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
while ([[clang::annotate_type("foo")]] bool b = false) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
if ([[clang::annotate_type("foo")]] bool b = false) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
try {
|
||||
} catch ([[clang::annotate_type("foo")]] int i) {
|
||||
} catch ([[clang::annotate_type("foo")]] int i) { // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
[[clang::annotate_type("foo")]] T var_template;
|
||||
[[clang::annotate_type("foo")]] extern "C" int extern_c_func();
|
||||
extern "C" [[clang::annotate_type("foo")]] int extern_c_func();
|
||||
[[clang::annotate_type("foo")]] T var_template; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
[[clang::annotate_type("foo")]] extern "C" int extern_c_func(); // expected-error {{an attribute list cannot appear here}}
|
||||
extern "C" [[clang::annotate_type("foo")]] int extern_c_func(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fdouble-square-bracket-attributes -verify %s
|
||||
static id __attribute((objc_gc(weak))) a;
|
||||
static id __attribute((objc_gc(strong))) b;
|
||||
|
||||
|
@ -18,6 +18,10 @@ static WEAK int h; // expected-warning {{'objc_ownership' only applies to Object
|
|||
/* expected-warning {{'__weak' only applies to Objective-C object or block pointer types; type here is 'int'}}*/ static __we\
|
||||
ak int i;
|
||||
|
||||
static id [[clang::objc_gc(weak)]] j;
|
||||
[[clang::objc_gc(weak)]] static id k; // expected-warning {{applying attribute 'objc_gc' to a declaration is deprecated; apply it to the type instead}}
|
||||
static id l [[clang::objc_gc(weak)]]; // expected-warning {{applying attribute 'objc_gc' to a declaration is deprecated; apply it to the type instead}}
|
||||
|
||||
// rdar://problem/9126213
|
||||
void test2(id __attribute((objc_gc(strong))) *strong,
|
||||
id __attribute((objc_gc(weak))) *weak) {
|
||||
|
|
|
@ -266,9 +266,9 @@ void func_multiple_addr2(void) {
|
|||
__attribute__((opencl_private)) private_int_t var5; // expected-warning {{multiple identical address spaces specified for type}}
|
||||
__attribute__((opencl_private)) private_int_t *var6; // expected-warning {{multiple identical address spaces specified for type}}
|
||||
#if __OPENCL_CPP_VERSION__
|
||||
[[clang::opencl_private]] __global int var7; // expected-error {{multiple address spaces specified for type}}
|
||||
[[clang::opencl_private]] __global int *var8; // expected-error {{multiple address spaces specified for type}}
|
||||
[[clang::opencl_private]] private_int_t var9; // expected-warning {{multiple identical address spaces specified for type}}
|
||||
[[clang::opencl_private]] private_int_t *var10; // expected-warning {{multiple identical address spaces specified for type}}
|
||||
__global int [[clang::opencl_private]] var7; // expected-error {{multiple address spaces specified for type}}
|
||||
__global int [[clang::opencl_private]] *var8; // expected-error {{multiple address spaces specified for type}}
|
||||
private_int_t [[clang::opencl_private]] var9; // expected-warning {{multiple identical address spaces specified for type}}
|
||||
private_int_t [[clang::opencl_private]] *var10; // expected-warning {{multiple identical address spaces specified for type}}
|
||||
#endif // !__OPENCL_CPP_VERSION__
|
||||
}
|
||||
|
|
|
@ -3739,7 +3739,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|||
if (!StmtSubjects.empty()) {
|
||||
OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
|
||||
OS << "const Decl *D) const override {\n";
|
||||
OS << " S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n";
|
||||
OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
|
||||
OS << " << AL << D->getLocation();\n";
|
||||
OS << " return false;\n";
|
||||
OS << "}\n\n";
|
||||
|
|
Loading…
Reference in New Issue