mboehme created this revision.
Herald added a reviewer: aaron.ballman.
Herald added a subscriber: jdoerfert.
Herald added a project: All.
mboehme requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: cfe-commits, sstefan1.
Herald added a project: clang.
(Iteration #4)
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 <https://reviews.llvm.org/D111548>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D126061
Files:
clang/include/clang/Basic/AttributeCommonInfo.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Parse/RAIIObjectsForParser.h
clang/include/clang/Sema/DeclSpec.h
clang/include/clang/Sema/ParsedAttr.h
clang/include/clang/Sema/Sema.h
clang/lib/Basic/Attributes.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Parse/ParseObjc.cpp
clang/lib/Parse/ParseStmt.cpp
clang/lib/Parse/ParseTemplate.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/ParsedAttr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaType.cpp
clang/test/Sema/annotate-type.c
clang/test/SemaCXX/address-space-placement.cpp
clang/test/SemaCXX/annotate-type.cpp
clang/test/SemaOpenCL/address-spaces.cl
clang/utils/TableGen/ClangAttrEmitter.cpp
Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3734,7 +3734,7 @@
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";
Index: clang/test/SemaOpenCL/address-spaces.cl
===================================================================
--- clang/test/SemaOpenCL/address-spaces.cl
+++ clang/test/SemaOpenCL/address-spaces.cl
@@ -266,9 +266,9 @@
__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__
}
Index: clang/test/SemaCXX/annotate-type.cpp
===================================================================
--- clang/test/SemaCXX/annotate-type.cpp
+++ clang/test/SemaCXX/annotate-type.cpp
@@ -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 @@
// 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 {{'annotate_type' attribute cannot be applied to a declaration}}
+extern "C" [[clang::annotate_type("foo")]] int extern_c_func(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}}
Index: clang/test/SemaCXX/address-space-placement.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/address-space-placement.cpp
@@ -0,0 +1,32 @@
+// 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.
+
+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}}
+
+ 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}}
+ }
+}
+
+[[clang::address_space(1)]] int* return_value(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+
+[[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}}
+
+struct [[clang::address_space(1)]] S { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+ [[clang::address_space(1)]] int* member_function(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+};
+
+template <class T>
+[[clang::address_space(1)]] T var_template; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}}
+
+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}}
Index: clang/test/Sema/annotate-type.c
===================================================================
--- clang/test/Sema/annotate-type.c
+++ clang/test/Sema/annotate-type.c
@@ -17,11 +17,8 @@
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 @@
}
// 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;
};
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -197,6 +197,10 @@
/// validating that noderef was used on a pointer or array.
bool parsedNoDeref;
+ // Set to indicate that, if we're currently processing the DeclSpec, the
+ // attributes we're seeing were actually written ahead of the declaration.
+ bool isProcessingDeclarationAttrs = false;
+
public:
TypeProcessingState(Sema &sema, Declarator &declarator)
: sema(sema), declarator(declarator),
@@ -224,7 +228,14 @@
chunkIndex = idx;
}
+ void setIsProcessingDeclarationAttrs(bool val) {
+ assert(isProcessingDeclSpec());
+ isProcessingDeclarationAttrs = val;
+ }
+
ParsedAttributesView &getCurrentAttributes() const {
+ if (isProcessingDeclarationAttrs)
+ return declarator.getDeclarationAttributes();
if (isProcessingDeclSpec())
return getMutableDeclSpec().getAttributes();
return declarator.getTypeObject(chunkIndex).getAttrs();
@@ -525,7 +536,8 @@
/// Distribute an objc_gc type attribute that was written on the
/// declarator.
static void distributeObjCPointerTypeAttrFromDeclarator(
- TypeProcessingState &state, ParsedAttr &attr, QualType &declSpecType) {
+ TypeProcessingState &state, ParsedAttributes &Attrs, ParsedAttr &attr,
+ QualType &declSpecType) {
Declarator &declarator = state.getDeclarator();
// objc_gc goes on the innermost pointer to something that's not a
@@ -562,8 +574,7 @@
// attribute from being applied multiple times and gives
// the source-location-filler something to work with.
state.saveDeclSpecAttrs();
- declarator.getMutableDeclSpec().getAttributes().takeOneFrom(
- declarator.getAttributes(), &attr);
+ declarator.getMutableDeclSpec().getAttributes().takeOneFrom(Attrs, &attr);
return;
}
}
@@ -571,15 +582,15 @@
// Otherwise, if we found an appropriate chunk, splice the attribute
// into it.
if (innermost != -1U) {
- moveAttrFromListToList(attr, declarator.getAttributes(),
+ moveAttrFromListToList(attr, Attrs,
declarator.getTypeObject(innermost).getAttrs());
return;
}
// Otherwise, diagnose when we're done building the type.
- declarator.getAttributes().remove(&attr);
+ Attrs.remove(&attr);
state.addIgnoredTypeAttr(attr);
-}
+ }
/// A function type attribute was written somewhere in a declaration
/// *other* than on the declarator itself or in the decl spec. Given
@@ -640,15 +651,6 @@
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))
@@ -659,25 +661,25 @@
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,
+ ParsedAttributes &Attrs,
ParsedAttr &attr,
QualType &declSpecType) {
- Declarator &declarator = state.getDeclarator();
-
// Try to distribute to the innermost.
- if (distributeFunctionTypeAttrToInnermost(
- state, attr, declarator.getAttributes(), declSpecType))
+ if (distributeFunctionTypeAttrToInnermost(state, attr, Attrs, declSpecType))
return;
// If that failed, diagnose the bad attribute when the declarator is
// fully built.
- declarator.getAttributes().remove(&attr);
+ Attrs.remove(&attr);
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.
///
@@ -686,15 +688,16 @@
/// 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,
+ ParsedAttributes &Attrs,
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.
- ParsedAttributesView AttrsCopy{state.getDeclarator().getAttributes()};
+ ParsedAttributesView AttrsCopy{Attrs};
for (ParsedAttr &attr : AttrsCopy) {
// Do not distribute [[]] attributes. They have strict rules for what
// they appertain to.
@@ -703,11 +706,13 @@
switch (attr.getKind()) {
OBJC_POINTER_TYPE_ATTRS_CASELIST:
- distributeObjCPointerTypeAttrFromDeclarator(state, attr, declSpecType);
+ distributeObjCPointerTypeAttrFromDeclarator(state, Attrs, attr,
+ declSpecType);
break;
FUNCTION_TYPE_ATTRS_CASELIST:
- distributeFunctionTypeAttrFromDeclarator(state, attr, declSpecType);
+ distributeFunctionTypeAttrFromDeclarator(state, Attrs, attr,
+ declSpecType);
break;
MS_TYPE_ATTRS_CASELIST:
@@ -1804,8 +1809,31 @@
// 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.slidesFromDeclToDeclSpec()) {
+ 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.
+ if (AL.isStandardAttributeSyntax() && AL.isClangScope()) {
+ S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
+ << AL;
+ }
+ }
+ }
+ state.setIsProcessingDeclarationAttrs(true);
+ processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs);
+ state.setIsProcessingDeclarationAttrs(false);
processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes());
+ }
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -3412,8 +3440,8 @@
break;
}
- if (!D.getAttributes().empty())
- distributeTypeAttrsFromDeclarator(state, T);
+ distributeTypeAttrsFromDeclarator(state, D.getDeclarationAttributes(), T);
+ distributeTypeAttrsFromDeclarator(state, D.getAttributes(), T);
// Find the deduced type in this type. Look in the trailing return type if we
// have one, otherwise in the DeclSpec type.
@@ -4712,7 +4740,8 @@
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;
@@ -5282,7 +5311,9 @@
// 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);
@@ -5696,7 +5727,14 @@
}
}
- // 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.slidesFromDeclToDeclSpec()) {
+ NonSlidingAttrs.addAtEnd(&AL);
+ }
+ }
+ processTypeAttrs(state, T, TAL_DeclName, NonSlidingAttrs);
processTypeAttrs(state, T, TAL_DeclName, D.getAttributes());
// Diagnose any ignored type attributes.
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -8312,15 +8312,15 @@
/// 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)
+ if (AL.isCXX11Attribute() && !Options.IncludeCXX11Attributes)
return;
// Unknown attributes are automatically warned on. Target-specific attributes
@@ -8353,14 +8353,29 @@
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");
- break;
+ }
+ if (AL.isTypeAttr()) {
+ if (Options.IgnoreTypeAttributes)
+ break;
+ if (AL.slidesFromDeclToDeclSpec()) {
+ if (AL.isStandardAttributeSyntax() && AL.isClangScope()) {
+ // 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.
+ S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
+ << AL << D->getLocation();
+ }
+ // GNU type attributes are handled elsewhere; 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:
@@ -9004,14 +9019,14 @@
/// 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
@@ -9099,7 +9114,9 @@
AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
for (const ParsedAttr &AL : AttrList) {
if (AL.getKind() == ParsedAttr::AT_Annotate) {
- ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute());
+ ProcessDeclAttributeOptions Options;
+ Options.IncludeCXX11Attributes = AL.isCXX11Attribute();
+ ProcessDeclAttribute(*this, nullptr, ASDecl, AL, Options);
} else {
Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
return true;
@@ -9133,6 +9150,7 @@
/// which might be lying around on it.
void Sema::checkUnusedDeclAttributes(Declarator &D) {
::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
+ ::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes());
::checkUnusedDeclAttributes(*this, D.getAttributes());
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs());
@@ -9241,18 +9259,34 @@
/// specified in many different places, and we need to find and apply them all.
void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// 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().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.
+ // Ordering of attributes can be important, so we first process the attributes
+ // from the declaration, and then those from the DeclSpec, as this corresponds
+ // to the order in which they appeared in the source code.
+ ParsedAttributesView NonSlidingAttrs;
+ for (ParsedAttr &AL : PD.getDeclarationAttributes()) {
+ if (!AL.slidesFromDeclToDeclSpec()) {
+ NonSlidingAttrs.addAtEnd(&AL);
+ }
+ }
+ ProcessDeclAttributeList(S, D, NonSlidingAttrs);
ProcessDeclAttributeList(S, D, PD.getAttributes());
// Apply additional attributes specified by '#pragma clang attribute'.
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -7027,7 +7027,8 @@
}
// 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
Index: clang/lib/Sema/ParsedAttr.cpp
===================================================================
--- clang/lib/Sema/ParsedAttr.cpp
+++ clang/lib/Sema/ParsedAttr.cpp
@@ -212,6 +212,40 @@
return getInfo().IsSupportedByPragmaAttribute;
}
+bool ParsedAttr::slidesFromDeclToDeclSpec() const {
+ if (!isTypeAttr())
+ return false;
+ if (!isStandardAttributeSyntax())
+ return true;
+
+ // We have historically allowed some 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.
+ 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_Regparm:
+ case AT_NoDeref:
+ case AT_ObjCGC:
+ case AT_VectorSize:
+ case AT_MatrixType:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
unsigned ParsedAttr::getSemanticSpelling() const {
@@ -265,3 +299,20 @@
diag::err_attribute_too_many_arguments,
std::greater<unsigned>());
}
+
+void clang::ConcatenateAttributes(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());
+}
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -740,6 +740,9 @@
/// 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 @@
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs);
+ ParsedAttributes DeclSpecAttrs(AttrFactory);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
}
case tok::kw_static:
@@ -939,7 +944,9 @@
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 @@
// 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 @@
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 @@
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 @@
}
DS.abort();
+ DS.takeAttributesFrom(Attrs);
const char *PrevSpec = nullptr;
unsigned DiagID;
@@ -1151,11 +1161,11 @@
if (getLangOpts().CPlusPlus && isTokenStringLiteral() &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
- Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File);
+ Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File, Attrs);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- return ParseDeclGroup(DS, DeclaratorContext::File);
+ return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
}
Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -242,11 +242,10 @@
// 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);
+ DeclaratorInfo.takeDeclarationAttributes(prefixAttrs);
if (TemplateInfo.TemplateParams)
DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -105,15 +105,21 @@
// 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);
+ ConcatenateAttributes(CXX11Attrs, GNUAttrs, Attrs);
+
assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
"attributes on empty statement");
@@ -158,7 +164,8 @@
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 @@
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);
+ ConcatenateAttributes(CXX11Attrs, GNUAttrs, Attrs);
+
// identifier ':' statement
return ParseLabeledStatement(Attrs, StmtCtx);
}
@@ -213,25 +226,29 @@
}
default: {
+ auto isStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); };
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
ParsedStmtContext()) &&
((GNUAttributeLoc.isValid() &&
- !(!Attrs.empty() &&
- llvm::all_of(
- Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) ||
+ !(!(CXX11Attrs.empty() && GNUAttrs.empty()) &&
+ llvm::all_of(CXX11Attrs, isStmtAttr) &&
+ llvm::all_of(GNUAttrs, isStmtAttr))) ||
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())
+ DeclStart = CXX11Attrs.Range.getBegin();
+ else if (GNUAttrs.Range.getBegin().isValid())
+ DeclStart = GNUAttrs.Range.getBegin();
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
@@ -245,7 +262,7 @@
case tok::kw___attribute: {
GNUAttributeLoc = Tok.getLocation();
- ParseGNUAttributes(Attrs);
+ ParseGNUAttributes(GNUAttrs);
goto Retry;
}
@@ -297,7 +314,8 @@
break;
case tok::kw_asm: {
- ProhibitAttributes(Attrs);
+ ProhibitAttributes(CXX11Attrs);
+ ProhibitAttributes(GNUAttrs);
bool msAsm = false;
Res = ParseAsmStatement(msAsm);
Res = Actions.ActOnFinishFullStmt(Res.get());
@@ -308,7 +326,8 @@
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 +337,8 @@
return ParseCXXTryBlock();
case tok::kw___try:
- ProhibitAttributes(Attrs); // TODO: is it correct?
+ ProhibitAttributes(CXX11Attrs); // TODO: is it correct?
+ ProhibitAttributes(GNUAttrs);
return ParseSEHTryBlock();
case tok::kw___leave:
@@ -327,55 +347,65 @@
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 +413,62 @@
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 +697,9 @@
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 +1168,9 @@
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 +2016,9 @@
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 +2389,9 @@
// 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 +2627,12 @@
MaybeParseCXX11Attributes(Attributes);
DeclSpec DS(AttrFactory);
- DS.takeAttributesFrom(Attributes);
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
Declarator ExDecl(DS, DeclaratorContext::CXXCatch);
+ ExDecl.takeDeclarationAttributes(Attributes);
ParseDeclarator(ExDecl);
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
} else
Index: clang/lib/Parse/ParseObjc.cpp
===================================================================
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -658,7 +658,7 @@
if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
SourceLocation DeclEnd;
allTUVariables.push_back(
- ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs));
+ ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs, attrs));
continue;
}
@@ -1231,6 +1231,7 @@
// Now actually move the attributes over.
takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes());
+ takeDeclAttributes(attrs, D.getDeclarationAttributes());
takeDeclAttributes(attrs, D.getAttributes());
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -2048,9 +2048,11 @@
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 +2063,9 @@
// 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 +2082,11 @@
// type-specifier-seq
DeclSpec DS(AttrFactory);
- DS.takeAttributesFrom(attrs);
ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition);
// declarator
Declarator DeclaratorInfo(DS, DeclaratorContext::Condition);
+ DeclaratorInfo.takeDeclarationAttributes(attrs);
ParseDeclarator(DeclaratorInfo);
// simple-asm-expr[opt]
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -342,7 +342,8 @@
/// 'extern' string-literal '{' declaration-seq[opt] '}'
/// 'extern' string-literal declaration
///
-Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
+Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context,
+ ParsedAttributes &DeclAttrs) {
assert(isTokenStringLiteral() && "Not a string literal!");
ExprResult Lang = ParseStringLiteralExpression(false);
@@ -354,8 +355,7 @@
getCurScope(), DS.getSourceRange().getBegin(), Lang.get(),
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
- ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
+ MaybeParseCXX11Attributes(DeclAttrs);
if (Tok.isNot(tok::l_brace)) {
// Reset the source range in DS, as the leading "extern"
@@ -364,7 +364,7 @@
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;
@@ -372,7 +372,7 @@
DS.abort();
- ProhibitAttributes(attrs);
+ ProhibitAttributes(DeclAttrs);
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
@@ -2676,23 +2676,24 @@
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);
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, DeclAttrs);
- // 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;
+ // We need to keep these attributes for future diagnostics
+ // before they are taken over by the declaration.
+ ParsedAttributesView FnAttrs;
+ FnAttrs.addAll(DeclAttrs.begin(), DeclAttrs.end());
+ FnAttrs.Range = DeclAttrs.Range;
- MaybeParseMicrosoftAttributes(attrs);
+ ParsedAttributes DeclSpecAttrs(AttrFactory);
+ MaybeParseMicrosoftAttributes(DeclSpecAttrs);
if (Tok.is(tok::kw_using)) {
// Eat 'using'.
@@ -2713,7 +2714,7 @@
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);
}
// Hold late-parsed attributes so we can attach a Decl to them later.
@@ -2722,7 +2723,8 @@
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this, TemplateDiags);
- DS.takeAttributesFrom(attrs);
+ DS.takeAttributesFrom(DeclSpecAttrs);
+
if (MalformedTypeSpec)
DS.SetTypeSpecError();
@@ -2774,6 +2776,7 @@
}
ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::Member);
+ DeclaratorInfo.takeDeclarationAttributes(DeclAttrs);
if (TemplateInfo.TemplateParams)
DeclaratorInfo.setTemplateParameterLists(TemplateParams);
VirtSpecifiers VS;
@@ -3072,7 +3075,7 @@
}
// Parse the next declarator.
- DeclaratorInfo.clear();
+ DeclaratorInfo.clearExceptDeclarationAttrs();
VS.clear();
BitfieldSize = ExprResult(/*Invalid=*/false);
EqualLoc = PureSpecLoc = SourceLocation();
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -1750,7 +1750,8 @@
///
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
@@ -1761,32 +1762,40 @@
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);
+ ConcatenateAttributes(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
@@ -1816,7 +1825,8 @@
/// 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) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
@@ -1833,7 +1843,8 @@
// 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);
+ ProhibitAttributes(DeclSpecAttrs);
DeclEnd = Tok.getLocation();
if (RequireSemi) ConsumeToken();
RecordDecl *AnonRecord = nullptr;
@@ -1850,8 +1861,8 @@
if (DeclSpecStart)
DS.SetRangeStart(*DeclSpecStart);
- DS.takeAttributesFrom(Attrs);
- return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
+ DS.takeAttributesFrom(DeclSpecAttrs);
+ return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
}
/// Returns true if this might be the start of a declarator, or a common typo
@@ -2006,10 +2017,12 @@
/// result.
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DeclaratorContext Context,
+ ParsedAttributes &Attrs,
SourceLocation *DeclEnd,
ForRangeInit *FRI) {
// Parse the first declarator.
ParsingDeclarator D(*this, DS, Context);
+ D.takeDeclarationAttributes(Attrs);
ParseDeclarator(D);
// Bail out if the first declarator didn't seem well-formed.
@@ -2172,7 +2185,7 @@
}
// Parse the next declarator.
- D.clear();
+ D.clearExceptDeclarationAttrs();
D.setCommaLoc(CommaLoc);
// Accept attributes in an init-declarator. In the first declarator in a
@@ -4300,7 +4313,6 @@
// Parse leading attributes.
ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
- DS.takeAttributesFrom(Attrs);
// Parse the common specifier-qualifiers-list piece.
ParseSpecifierQualifierList(DS);
@@ -4308,6 +4320,11 @@
// 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 draft 6.7.2.1/9 : "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);
@@ -4321,6 +4338,7 @@
SourceLocation CommaLoc;
while (true) {
ParsingFieldDeclarator DeclaratorInfo(*this, DS);
+ DeclaratorInfo.D.takeDeclarationAttributes(Attrs);
DeclaratorInfo.D.setCommaLoc(CommaLoc);
// Attributes are only allowed here on successive declarators.
@@ -4361,6 +4379,10 @@
return;
FirstDeclarator = false;
+
+ // Take the attributes back from the Declarator before we destroy it, so we
+ // can put them on the next field.
+ Attrs.takeAllFrom(DeclaratorInfo.D.getDeclarationAttributes());
}
}
@@ -6597,9 +6619,9 @@
/// 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.
@@ -6901,7 +6923,7 @@
///
/// 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.
@@ -6954,22 +6976,25 @@
DeclSpec DS(AttrFactory);
// Parse any C++11 attributes.
- MaybeParseCXX11Attributes(DS.getAttributes());
+ ParsedAttributes ArgDeclAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(ArgDeclAttrs);
- // Skip any Microsoft attributes before a param.
- MaybeParseMicrosoftAttributes(DS.getAttributes());
-
- SourceLocation DSStart = Tok.getLocation();
+ ParsedAttributes ArgDeclSpecAttrs(AttrFactory);
// 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);
+ ArgDeclSpecAttrs.takeAllFrom(FirstArgAttrs);
- ParseDeclarationSpecifiers(DS);
+ // Skip any Microsoft attributes before a param.
+ MaybeParseMicrosoftAttributes(ArgDeclSpecAttrs);
+
+ SourceLocation DSStart = Tok.getLocation();
+ ParseDeclarationSpecifiers(DS);
+ DS.takeAttributesFrom(ArgDeclSpecAttrs);
// Parse the declarator. This is "PrototypeContext" or
// "LambdaExprParameterContext", because we must accept either
@@ -6980,6 +7005,7 @@
: DeclaratorCtx == DeclaratorContext::LambdaExpr
? DeclaratorContext::LambdaExprParameter
: DeclaratorContext::Prototype);
+ ParmDeclarator.takeDeclarationAttributes(ArgDeclAttrs);
ParseDeclarator(ParmDeclarator);
// Parse GNU attributes, if present.
Index: clang/lib/Basic/Attributes.cpp
===================================================================
--- clang/lib/Basic/Attributes.cpp
+++ clang/lib/Basic/Attributes.cpp
@@ -85,6 +85,10 @@
return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
}
+bool AttributeCommonInfo::isClangScope() const {
+ return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"));
+}
+
#include "clang/Sema/AttrParsedAttrKinds.inc"
static SmallString<64> normalizeName(const IdentifierInfo *Name,
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -4423,8 +4423,38 @@
// 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);
Index: clang/include/clang/Sema/ParsedAttr.h
===================================================================
--- clang/include/clang/Sema/ParsedAttr.h
+++ clang/include/clang/Sema/ParsedAttr.h
@@ -651,6 +651,16 @@
bool isKnownToGCC() const;
bool isSupportedByPragmaAttribute() const;
+ /// Returns whether the 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).
+ /// Attributes with GNU, __declspec or keyword syntax generally slide
+ /// to the decl-specifier-seq. C++11 attributes specified ahead of the
+ /// declaration always appertain to the declaration according to the standard,
+ /// but historically we have allowed some of these attributes to slide to
+ /// the decl-specifier-seq too, so we need to keep supporting this behavior.
+ bool slidesFromDeclToDeclSpec() 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
@@ -1103,6 +1113,11 @@
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 ConcatenateAttributes(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 {
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -1853,6 +1853,8 @@
/// Attrs - Attributes.
ParsedAttributes Attrs;
+ ParsedAttributes DeclarationAttrs;
+
/// The asm label, if specified.
Expr *AsmLabel;
@@ -1899,7 +1901,8 @@
Redeclaration(false), Extension(false), ObjCIvar(false),
ObjCWeakProperty(false), InlineStorageUsed(false),
HasInitializer(false), Attrs(ds.getAttributePool().getFactory()),
- AsmLabel(nullptr), TrailingRequiresClause(nullptr),
+ DeclarationAttrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
+ TrailingRequiresClause(nullptr),
InventedTemplateParameterList(nullptr) {}
~Declarator() {
@@ -1971,6 +1974,14 @@
/// Reset the contents of this Declarator.
void clear() {
+ clearExceptDeclarationAttrs();
+ DeclarationAttrs.clear();
+ }
+
+ /// Reset the contents of this Declarator, except for the declaration
+ /// attributes. The intent is that the declaration attributes can be reused
+ /// for multiple declarators in the same declaration.
+ void clearExceptDeclarationAttrs() {
SS.clear();
Name.clear();
Range = DS.getSourceRange();
@@ -2520,12 +2531,31 @@
SetRangeEnd(attrs.Range.getEnd());
}
+ /// takeDeclarationAttributes - Takes attributes from the given
+ /// parsed-attributes set and associates them with the declaration (rather
+ /// than the declarator).
+ ///
+ /// 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.
+ void takeDeclarationAttributes(ParsedAttributes &attrs) {
+ DeclarationAttrs.takeAllFrom(attrs);
+ }
+
const ParsedAttributes &getAttributes() const { return Attrs; }
ParsedAttributes &getAttributes() { return Attrs; }
+ const ParsedAttributes &getDeclarationAttributes() const {
+ return DeclarationAttrs;
+ }
+ ParsedAttributes &getDeclarationAttributes() { 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())
Index: clang/include/clang/Parse/RAIIObjectsForParser.h
===================================================================
--- clang/include/clang/Parse/RAIIObjectsForParser.h
+++ clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -213,8 +213,8 @@
return const_cast<ParsingDeclSpec&>(getDeclSpec());
}
- void clear() {
- Declarator::clear();
+ void clearExceptDeclarationAttrs() {
+ Declarator::clearExceptDeclarationAttrs();
ParsingRAII.reset();
}
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -2066,7 +2066,8 @@
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);
@@ -2307,15 +2308,18 @@
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,
@@ -3015,7 +3019,8 @@
unsigned int index, SourceLocation &InlineLoc,
ParsedAttributes &attrs,
BalancedDelimiterTracker &Tracker);
- Decl *ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context);
+ Decl *ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context,
+ ParsedAttributes &DeclAttrs);
Decl *ParseExportDeclaration();
DeclGroupPtrTy ParseUsingDirectiveOrDeclaration(
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3381,8 +3381,11 @@
"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 "
Index: clang/include/clang/Basic/AttributeCommonInfo.h
===================================================================
--- clang/include/clang/Basic/AttributeCommonInfo.h
+++ clang/include/clang/Basic/AttributeCommonInfo.h
@@ -146,6 +146,7 @@
bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
bool isGNUScope() const;
+ bool isClangScope() const;
bool isAlignasAttribute() const {
// FIXME: Use a better mechanism to determine this.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits