diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 3b1dac348e..e849e05c7b 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -463,6 +463,15 @@ 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.isCXX11Attribute()) { + moveAttrFromListToList(attr, state.getCurrentAttrListRef(), + state.getDeclarator().getAttrListRef()); + return; + } + // Try to distribute to the innermost. if (distributeFunctionTypeAttrToInnermost(state, attr, state.getCurrentAttrListRef(), @@ -512,6 +521,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, do { next = attr->getNext(); + // Do not distribute C++11 attributes. They have strict rules for what + // they appertain to. + if (attr->isCXX11Attribute()) + continue; + switch (attr->getKind()) { OBJC_POINTER_TYPE_ATTRS_CASELIST: distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm index ad54208286..9ad85d310f 100644 --- a/test/Parser/objcxx11-attributes.mm +++ b/test/Parser/objcxx11-attributes.mm @@ -44,7 +44,7 @@ void f(X *noreturn) { int e2(); // expected-warning {{interpreted as a function declaration}} expected-note{{}} // A function taking a noreturn function. - int(f)([[noreturn]] int()); // expected-note {{here}} + int(f)([[gnu::noreturn]] int ()); // expected-note {{here}} f(e); f(e2); // expected-error {{cannot initialize a parameter of type 'int (*)() __attribute__((noreturn))' with an lvalue of type 'int ()'}} diff --git a/test/SemaCXX/cxx11-gnu-attrs.cpp b/test/SemaCXX/cxx11-gnu-attrs.cpp index fdcb75057e..a9fcee3da3 100644 --- a/test/SemaCXX/cxx11-gnu-attrs.cpp +++ b/test/SemaCXX/cxx11-gnu-attrs.cpp @@ -39,7 +39,17 @@ void deprecated3() { void nonnull [[gnu::nonnull]] (); // expected-warning {{applied to function with no pointer arguments}} +// [[gnu::noreturn]] appertains to a declaration, and marks the innermost +// function declarator in that declaration as being noreturn. int noreturn [[gnu::noreturn]]; // expected-warning {{'noreturn' only applies to function types}} +int noreturn_fn_1(); +int noreturn_fn_2() [[gnu::noreturn]]; // expected-warning {{cannot be applied to a type}} +int noreturn_fn_3 [[gnu::noreturn]] (); +[[gnu::noreturn]] int noreturn_fn_4(); +int (*noreturn_fn_ptr_1 [[gnu::noreturn]])() = &noreturn_fn_1; // expected-error {{cannot initialize}} +int (*noreturn_fn_ptr_2 [[gnu::noreturn]])() = &noreturn_fn_3; +[[gnu::noreturn]] int (*noreturn_fn_ptr_3)() = &noreturn_fn_1; // expected-error {{cannot initialize}} +[[gnu::noreturn]] int (*noreturn_fn_ptr_4)() = &noreturn_fn_3; struct [[gnu::packed]] packed { char c; int n; }; static_assert(sizeof(packed) == sizeof(char) + sizeof(int), "not packed");