summaryrefslogtreecommitdiff
path: root/test/Misc
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-04-18 14:33:39 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-04-18 14:33:39 +0000
commit4bbde6cf2a280972796e32e11777eb69d466e56b (patch)
tree798ca5030e2add2471363b39e5d311e401c14265 /test/Misc
parent6730a5e41ee7ce17daecbdf29ca50071a18eb919 (diff)
Add #pragma clang attribute
This is a recommit of r300539 that was reverted in r300543 due to test failures. The original commit message is displayed below: The new '#pragma clang attribute' directive can be used to apply attributes to multiple declarations. An attribute must satisfy the following conditions to be supported by the pragma: - It must have a subject list that's defined in the TableGen file. - It must be documented. - It must not be late parsed. - It must have a GNU/C++11 spelling. Differential Revision: https://reviews.llvm.org/D30009 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@300556 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Misc')
-rw-r--r--test/Misc/pragma-attribute-cxx-subject-match-rules.cpp169
-rw-r--r--test/Misc/pragma-attribute-cxx.cpp106
-rw-r--r--test/Misc/pragma-attribute-objc-subject-match-rules.m113
-rw-r--r--test/Misc/pragma-attribute-objc.m164
-rw-r--r--test/Misc/pragma-attribute-strict-subjects.c222
-rw-r--r--test/Misc/pragma-attribute-supported-attributes-list.test62
6 files changed, 836 insertions, 0 deletions
diff --git a/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp b/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp
new file mode 100644
index 0000000000..b7741343ad
--- /dev/null
+++ b/test/Misc/pragma-attribute-cxx-subject-match-rules.cpp
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=namespace" %s | FileCheck --check-prefix=CHECK-NAMESPACE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=type_alias" %s | FileCheck --check-prefix=CHECK-TYPE_ALIAS %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=enum" %s | FileCheck --check-prefix=CHECK-ENUM %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=enum_constant" %s | FileCheck --check-prefix=CHECK-ENUM_CONSTANT %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=record" %s | FileCheck --check-prefix=CHECK-RECORD %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=record(unless(is_union))" %s | FileCheck --check-prefix=CHECK-RECORD_UNLESS_IS_UNION %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=field" %s | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=function" %s | FileCheck --check-prefix=CHECK-FUNCTION %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=hasType(functionType)" %s | FileCheck --check-prefix=CHECK-HAS_TYPE_FUNCTION_TYPE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=function(is_member)" %s | FileCheck --check-prefix=CHECK-FUNCTION_IS_MEMBER %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable" %s | FileCheck --check-prefix=CHECK-VARIABLE %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(is_global)" %s | FileCheck --check-prefix=CHECK-VARIABLE_IS_GLOBAL %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(is_parameter)" %s | FileCheck --check-prefix=CHECK-VARIABLE_IS_PARAMETER %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=variable(unless(is_parameter))" %s | FileCheck --check-prefix=CHECK-VARIABLE_UNLESS_IS_PARAMETER %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(SUBJECT))
+
+namespace testNamespace {
+// CHECK-NAMESPACE: NamespaceDecl{{.*}} testNamespace
+// CHECK-NAMESPACE-NEXT: AnnotateAttr{{.*}} "test"
+
+typedef int testTypedef;
+// CHECK-TYPE_ALIAS: TypedefDecl{{.*}} testTypedef
+// CHECK-TYPE_ALIAS-NEXT: BuiltinType
+// CHECK-TYPE_ALIAS-NEXT: AnnotateAttr{{.*}} "test"
+
+using testTypeAlias = double;
+// CHECK-TYPE_ALIAS: TypeAliasDecl{{.*}} testTypeAlias
+// CHECK-TYPE_ALIAS-NEXT: BuiltinType
+// CHECK-TYPE_ALIAS-NEXT: AnnotateAttr{{.*}} "test"
+
+enum testEnum {
+ testEnumCase1,
+ testEnumCase2
+};
+// CHECK-ENUM: EnumDecl{{.*}} testEnum
+// CHECK-ENUM-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-ENUM_CONSTANT: EnumConstantDecl{{.*}} testEnumCase1
+// CHECK-ENUM_CONSTANT-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-ENUM_CONSTANT: EnumConstantDecl{{.*}} testEnumCase2
+// CHECK-ENUM_CONSTANT-NEXT: AnnotateAttr{{.*}} "test"
+
+struct testStructRecord {
+ int testStructRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testStructRecord
+// CHECK-RECORD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testStructRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testStructRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+class testClassRecord {
+ int testClassRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testClassRecord
+// CHECK-RECORD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testClassRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testClassRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+union testUnionRecord {
+ int testUnionRecordField;
+};
+// CHECK-RECORD: CXXRecordDecl{{.*}} testUnionRecord
+// CHECK-RECORD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl{{.*}} testUnionRecord
+// CHECK-RECORD_UNLESS_IS_UNION-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-FIELD: FieldDecl{{.*}} testUnionRecordField
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+// CHECK-RECORD_UNLESS_IS_UNION-LABEL: CXXRecordDecl
+void testFunctionDecl();
+// CHECK-FUNCTION: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+
+void testFunctionDecl() { }
+// CHECK-FUNCTION: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-FUNCTION-NEXT: CompoundStmt
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: FunctionDecl{{.*}} testFunctionDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+
+void (*testFunctionVar)();
+// CHECK-HAS_TYPE_FUNCTION_TYPE: VarDecl{{.*}} testFunctionVar
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// 'function' should not apply to variables with a function type!
+// CHECK-FUNCTION: VarDecl{{.*}} testFunctionVar
+// CHECK-FUNCTION-NOT: AnnotateAttr{{.*}} "test"
+
+class testMethods {
+ testMethods();
+ void testMethod();
+};
+void testMethods::testMethod() { }
+void testFunctionNotMethod();
+// CHECK-FUNCTION-LABEL: CXXConstructorDecl{{.*}} testMethods
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXConstructorDecl{{.*}} testMethods
+// CHECK-FUNCTION_IS_MEMBER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXConstructorDecl{{.*}} testMethods
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION_IS_MEMBER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXMethodDecl{{.*}} testMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION-NEXT: CompoundStmt
+// CHECK-FUNCTION-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: CXXMethodDecl{{.*}} testMethod
+// CHECK-FUNCTION_IS_MEMBER-NEXT: CompoundStmt
+// CHECK-CXX_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE: CXXMethodDecl{{.*}} testMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-FUNCTION_IS_MEMBER: FunctionDecl{{.*}} testFunctionNotMethod
+// CHECK-FUNCTION_IS_MEMBER-NOT: AnnotateAttr{{.*}} "test"
+
+int testVariable;
+// CHECK-VARIABLE: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_IS_GLOBAL-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testVariable
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+void testVarFunction(int testParam) {
+// CHECK-VARIABLE: VarDecl{{.*}} testParam
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_IS_GLOBAL-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testParam
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+
+ int testLocalVariable;
+// CHECK-VARIABLE: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_IS_GLOBAL-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testLocalVariable
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+}
+class testVarClass {
+ static int testStaticVar;
+};
+// CHECK-VARIABLE: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_GLOBAL-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_IS_GLOBAL-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_IS_PARAMETER-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_IS_PARAMETER-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-LABEL: VarDecl{{.*}} testStaticVar
+// CHECK-VARIABLE_UNLESS_IS_PARAMETER-NEXT: AnnotateAttr{{.*}} "test"
+
+
+}
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-cxx.cpp b/test/Misc/pragma-attribute-cxx.cpp
new file mode 100644
index 0000000000..c241c4e4bd
--- /dev/null
+++ b/test/Misc/pragma-attribute-cxx.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump -ast-dump-filter test -std=c++11 -fcxx-exceptions %s | FileCheck %s
+// expected-no-diagnostics
+
+class testClass1 {
+};
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClass1
+// CHECK-NOT: AnnotateAttr
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to=any(record, field, variable, function, namespace, type_alias))
+
+class testClass2 {
+ void testMethod1(int param);
+
+ testClass2();
+
+ testClass2 *operator -> ();
+};
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClass2
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK: CXXMethodDecl{{.*}} testMethod1
+// CHECK-NEXT: ParmVarDecl{{.*}} param
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CXXConstructorDecl
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CXXMethodDecl{{.*}} operator->
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+#pragma clang attribute push (__attribute__((annotate("method"))), apply_to=any(record, field, variable, function, namespace, type_alias))
+
+void testClass2::testMethod1(int param) {
+
+#pragma clang attribute pop
+}
+// CHECK-LABEL: CXXMethodDecl{{.*}}prev{{.*}} testMethod1
+// CHECK-NEXT: ParmVarDecl{{.*}} param
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "method"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "method"
+
+namespace testNamespace {
+}
+// CHECK-LABEL: NamespaceDecl{{.*}} testNamespace
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+class testClassForward;
+// CHECK-LABEL: CXXRecordDecl{{.*}} testClassForward
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+namespace testNamespaceAlias = testNamespace;
+// CHECK-LABEL: NamespaceAliasDecl{{.*}} testNamespaceAlias
+// CHECK-NOT: AnnotateAttr
+
+using testTypeAlias = testClass2;
+// CHECK-LABEL: TypeAliasDecl{{.*}} testTypeAlias
+// CHECK: AnnotateAttr{{.*}} "test"
+
+void testCatchVariable() {
+ try {
+ } catch (int testCatch) {
+ }
+ testCatchVariable();
+}
+// CHECK-LABEL: FunctionDecl{{.*}} testCatchVariable
+// CHECK: CXXCatchStmt
+// CHECK-NEXT: VarDecl{{.*}} testCatch
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+void testLambdaMethod() {
+ auto l = [] () { };
+ testLambdaMethod();
+}
+// CHECK-LABEL: FunctionDecl{{.*}} testLambdaMethod
+// CHECK: LambdaExpr
+// CHECK-NEXT: CXXRecordDecl
+// CHECK-NEXT: CXXMethodDecl{{.*}} operator()
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((require_constant_initialization)), apply_to=variable(is_global))
+
+int testCI1 = 1;
+// CHECK-LABEL: VarDecl{{.*}} testCI1
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: RequireConstantInitAttr
+
+#pragma clang attribute pop
+
+int testNoCI = 0;
+// CHECK-LABEL: VarDecl{{.*}} testNoCI
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NOT: RequireConstantInitAttr
+
+// Check support for CXX11 style attributes
+#pragma clang attribute push ([[noreturn]], apply_to = function)
+
+void testNoReturn();
+// CHECK-LABEL: FunctionDecl{{.*}} testNoReturn
+// CHECK-NEXT: CXX11NoReturnAttr
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-objc-subject-match-rules.m b/test/Misc/pragma-attribute-objc-subject-match-rules.m
new file mode 100644
index 0000000000..09ab5e1f33
--- /dev/null
+++ b/test/Misc/pragma-attribute-objc-subject-match-rules.m
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump "-DSUBJECT=objc_interface" %s | FileCheck --check-prefix=CHECK-OBJC_INTERFACE %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_protocol" %s | FileCheck --check-prefix=CHECK-OBJC_PROTOCOL %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump "-DSUBJECT=objc_category" %s | FileCheck --check-prefix=CHECK-OBJC_CATEGORY %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_method" %s | FileCheck --check-prefix=CHECK-OBJC_METHOD %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_method(is_instance)" %s | FileCheck --check-prefix=CHECK-OBJC_METHOD_IS_INSTANCE %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=field" %s | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=objc_property" %s | FileCheck --check-prefix=CHECK-OBJC_PROPERTY %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=block" %s | FileCheck --check-prefix=CHECK-BLOCK %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -Wno-objc-root-class -fsyntax-only -ast-dump -ast-dump-filter test "-DSUBJECT=hasType(functionType)" %s | FileCheck --check-prefix=CHECK-HAS_TYPE_FUNCTION_TYPE %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(SUBJECT))
+
+@interface testInterface
+@end
+// CHECK-OBJC_INTERFACE: ObjCInterfaceDecl{{.*}} testInterface
+// CHECK-OBJC_INTERFACE-NEXT: AnnotateAttr{{.*}} "test"
+
+@interface testInterface ()
+@end
+// CHECK-OBJC_INTERFACE: ObjCCategoryDecl
+// CHECK-OBJC_INTERFACE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_CATEGORY: ObjCCategoryDecl
+// CHECK-OBJC_CATEGORY-NEXT: ObjCInterface
+// CHECK-OBJC_CATEGORY-NEXT: AnnotateAttr{{.*}} "test"
+
+@interface testInterface (testCategory)
+@end
+// CHECK-OBJC_INTERFACE: ObjCCategoryDecl{{.*}} testCategory
+// CHECK-OBJC_INTERFACE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_CATEGORY: ObjCCategoryDecl{{.*}} testCategory
+// CHECK-OBJC_CATEGORY-NEXT: ObjCInterface
+// CHECK-OBJC_CATEGORY-NEXT: AnnotateAttr{{.*}} "test"
+
+// CHECK-OBJC_INTERFACE-LABEL: ObjCProtocolDecl
+@protocol testProtocol
+@end
+// CHECK-OBJC_PROTOCOL: ObjCProtocolDecl{{.*}} testProtocol
+// CHECK-OBJC_PROTOCOL-NEXT: AnnotateAttr{{.*}} "test"
+
+@interface methodContainer
+- (void) testInstanceMethod;
++ (void) testClassMethod;
+@end
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+
+@implementation methodContainer
+- (void) testInstanceMethod { }
++ (void) testClassMethod { }
+@end
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: ImplicitParamDecl
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: CompoundStmt
+// CHECK-OBJC_METHOD_IS_INSTANCE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-OBJC_METHOD_IS_INSTANCE: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-OBJC_METHOD_IS_INSTANCE-NOT: AnnotateAttr{{.*}} "test"
+
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testInstanceMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: ObjCMethodDecl{{.*}} testClassMethod
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+@interface propertyContainer {
+ int testIvar;
+// CHECK-FIELD: ObjCIvarDecl{{.*}} testIvar
+// CHECK-FIELD-NEXT: AnnotateAttr{{.*}} "test"
+
+}
+@property int testProperty;
+// CHECK-OBJC_PROPERTY: ObjCPropertyDecl{{.*}} testProperty
+// CHECK-OBJC_PROPERTY-NEXT: AnnotateAttr{{.*}} "test"
+
+@end
+
+void (^testBlockVar)();
+// CHECK-BLOCK: VarDecl{{.*}} testBlockVar
+// CHECK-BLOCK-NOT: AnnotateAttr{{.*}} "test"
+
+void testBlock() {
+ (void)(^ { });
+}
+// CHECK-BLOCK-LABEL: BlockDecl
+// CHECK-BLOCK-NEXT: CompoundStmt
+// CHECK-BLOCK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-LABEL: FunctionDecl{{.*}} testBlock
+// CHECK-HAS_TYPE_FUNCTION_TYPE: BlockDecl
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: CompoundStmt
+// The attribute applies to function, but not to block:
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-HAS_TYPE_FUNCTION_TYPE-NOT: AnnotateAttr{{.*}} "test"
+
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-objc.m b/test/Misc/pragma-attribute-objc.m
new file mode 100644
index 0000000000..541cfa9ad3
--- /dev/null
+++ b/test/Misc/pragma-attribute-objc.m
@@ -0,0 +1,164 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+#pragma clang attribute push (__attribute__((annotate("test"))), apply_to = any(objc_interface, objc_protocol, objc_property, field, objc_method, variable))
+#pragma clang attribute push (__attribute__((objc_subclassing_restricted)), apply_to = objc_interface)
+
+@interface testInterface1
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface1
+// CHECK-NEXT: ObjCImplementation
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr{{.*}}
+
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+{
+ int testIvar1;
+ // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar1
+ // CHECK-NEXT: AnnotateAttr{{.*}} "test"
+ // CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
+@property int testProp1;
+// CHECK-LABEL: ObjCPropertyDecl{{.*}} testProp1
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+- (void)testIm:(int) x;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testIm
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
++ (void)testCm;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testCm
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+// Implicit getters/setters shouldn't receive the attributes.
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testProp1
+// CHECK-NOT: AnnotateAttr
+// CHECK-LABEL: ObjCMethodDecl{{.*}}setTestProp1
+// CHECK-NOT: AnnotateAttr
+
+@end
+
+// @implementation can't receive explicit attributes, so don't add the pragma
+// attributes to them.
+@implementation testInterface1
+// CHECK-LABEL: ObjCImplementationDecl{{.*}}testInterface1
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+{
+ int testIvar2;
+ // CHECK-LABEL: ObjCIvarDecl{{.*}} testIvar2
+ // CHECK-NEXT: AnnotateAttr{{.*}} "test"
+ // CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
+// Don't add attributes to implicit parameters!
+- (void)testIm:(int) x {
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testIm
+// CHECK-NEXT: ImplicitParamDecl
+// CHECK-NEXT: ImplicitParamDecl
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+}
+
++ (void)testCm {
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testCm
+// CHECK: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NOT: AnnotateAttr
+ _Pragma("clang attribute push (__attribute__((annotate(\"applied at container start\"))), apply_to=objc_interface)");
+}
+
+// Implicit ivars shouldn't receive the attributes.
+// CHECK-LABEL: ObjCIvarDecl{{.*}}_testProp1
+// CHECK-NOT: AnnotateAttr
+
+@end
+
+@implementation testImplWithoutInterface // expected-warning {{cannot find interface declaration for 'testImplWithoutInterface'}}
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testImplWithoutInterface
+// CHECK-NEXT: ObjCImplementation
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NEXT: ObjCSubclassingRestrictedAttr
+// CHECK-NEXT: AnnotateAttr{{.*}} "applied at container start"
+
+// CHECK-LABEL: ObjCImplementationDecl{{.*}}testImplWithoutInterface
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+#pragma clang attribute pop
+
+@protocol testProtocol
+// CHECK-LABEL: ObjCProtocolDecl{{.*}}testProtocol
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+// CHECK-NOT: AnnotateAttr
+
+- (void)testProtIm;
+// CHECK-LABEL: ObjCMethodDecl{{.*}}testProtIm
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+@protocol testForwardProtocol;
+// CHECK-LABEL: ObjCProtocolDecl{{.*}}testForwardProtocol
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+
+// Categories can't receive explicit attributes, so don't add pragma attributes
+// to them.
+@interface testInterface1(testCat)
+// CHECK-LABEL: ObjCCategoryDecl{{.*}}testCat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+@implementation testInterface1(testCat)
+// CHECK-LABEL: ObjCCategoryImplDecl{{.*}}testCat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@end
+
+// @class/@compatibility_alias declarations can't receive explicit attributes,
+// so don't add pragma attributes to them.
+@class testClass;
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testClass
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+@compatibility_alias testCompat testInterface1;
+// CHECK-LABEL: ObjCCompatibleAliasDecl{{.*}}testCompat
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+
+#pragma clang attribute pop // objc_subclassing_restricted
+
+@interface testInterface3
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface3
+// CHECK-NEXT: AnnotateAttr{{.*}} "test"
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+@end
+
+#pragma clang attribute pop // annotate("test")
+
+@interface testInterface4
+// CHECK-LABEL: ObjCInterfaceDecl{{.*}}testInterface4
+// CHECK-NOT: AnnotateAttr
+// CHECK-NOT: ObjCSubclassingRestrictedAttr
+@end
diff --git a/test/Misc/pragma-attribute-strict-subjects.c b/test/Misc/pragma-attribute-strict-subjects.c
new file mode 100644
index 0000000000..ecd551bee6
--- /dev/null
+++ b/test/Misc/pragma-attribute-strict-subjects.c
@@ -0,0 +1,222 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-pragma-clang-attribute -verify %s
+// RUN: not %clang_cc1 -fsyntax-only -ast-dump -ast-dump-filter test %s | FileCheck %s
+
+// Check for contradictions in rules for attribute without a strict subject set:
+
+#pragma clang attribute push (__attribute__((annotate("subRuleContradictions"))), apply_to = any(variable, variable(is_parameter), function(is_member), variable(is_global)))
+// expected-error@-1 {{redundant attribute subject matcher sub-rule 'variable(is_parameter)'; 'variable' already matches those declarations}}
+// expected-error@-2 {{redundant attribute subject matcher sub-rule 'variable(is_global)'; 'variable' already matches those declarations}}
+
+// Ensure that we've recovered from the error:
+int testRecoverSubRuleContradiction = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverSubRuleContradiction
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AnnotateAttr{{.*}} "subRuleContradictions"
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global)))
+// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}}
+// We have just one error, don't error on 'variable(is_global)'
+
+// Ensure that we've recovered from the error:
+int testRecoverNegatedContradiction = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverNegatedContradiction
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AnnotateAttr{{.*}} "negatedSubRuleContradictions2"
+
+void testRecoverNegatedContradictionFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverNegatedContradictionFunc
+// CHECK-NEXT: AnnotateAttr{{.*}} "negatedSubRuleContradictions2"
+
+#pragma clang attribute pop
+
+// Verify the strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+int testRecoverStrictnessVar = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverStrictnessVar
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NOT: AbiTagAttr
+
+void testRecoverStrictnessFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverStrictnessFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testRecoverStrictnessStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testRecoverStrictnessStruct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, record(unless(is_union)), variable, enum))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+int testRecoverExtraVar = 0;
+// CHECK-LABEL: VarDecl{{.*}} testRecoverExtraVar
+// CHECK-NEXT: IntegerLiteral
+// CHECK-NEXT: AbiTagAttr
+
+void testRecoverExtraFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testRecoverExtraFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testRecoverExtraStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testRecoverExtraStruct
+// CHECK-NEXT: AbiTagAttr
+
+enum testNoEnumAbiTag { CaseCase };
+// CHECK-LABEL: EnumDecl{{.*}} testNoEnumAbiTag
+// CHECK-NO: AbiTagAttr
+
+#pragma clang attribute pop
+
+// Verify the non-strict subject set verification.
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function))
+
+int testSubset1Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset1Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset1Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset1Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset1Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset1Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = variable)
+
+int testSubset2Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset2Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset2Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset2Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset2Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset2Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union))))
+
+int testSubset3Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset3Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset3Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset3Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset3Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset3Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(function, variable))
+
+int testSubset4Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset4Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset4Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset4Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset4Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset4Struct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(variable, record(unless(is_union))))
+
+int testSubset5Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset5Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset5Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset5Func
+// CHECK-NOT: AbiTagAttr
+
+struct testSubset5Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset5Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function))
+
+int testSubset6Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset6Var
+// CHECK-NOT: AbiTagAttr
+
+void testSubset6Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset6Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset6Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset6Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable))
+
+int testSubset7Var;
+// CHECK-LABEL: VarDecl{{.*}} testSubset7Var
+// CHECK-NEXT: AbiTagAttr
+
+void testSubset7Func(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubset7Func
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubset7Struct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubset7Struct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = any(record(unless(is_union)), function, variable, enum, enum_constant))
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum_constant', and 'enum'}}
+
+int testSubsetRecoverVar;
+// CHECK-LABEL: VarDecl{{.*}} testSubsetRecoverVar
+// CHECK-NEXT: AbiTagAttr
+
+void testSubsetRecoverFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubsetRecoverFunc
+// CHECK-NEXT: AbiTagAttr
+
+struct testSubsetRecoverStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubsetRecoverStruct
+// CHECK-NEXT: AbiTagAttr
+
+#pragma clang attribute pop
+
+#pragma clang attribute push (__attribute__((abi_tag("a"))), apply_to = enum)
+// expected-error@-1 {{attribute 'abi_tag' can't be applied to 'enum'}}
+
+int testSubsetNoVar;
+// CHECK-LABEL: VarDecl{{.*}} testSubsetNoVar
+// CHECK-NOT: AbiTagAttr
+
+void testSubsetNoFunc(void);
+// CHECK-LABEL: FunctionDecl{{.*}} testSubsetNoFunc
+// CHECK-NOT: AbiTagAttr
+
+struct testSubsetNoStruct { };
+// CHECK-LABEL: RecordDecl{{.*}} testSubsetNoStruct
+// CHECK-NOT: AbiTagAttr
+
+#pragma clang attribute pop
diff --git a/test/Misc/pragma-attribute-supported-attributes-list.test b/test/Misc/pragma-attribute-supported-attributes-list.test
new file mode 100644
index 0000000000..b1f2e66ab3
--- /dev/null
+++ b/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -0,0 +1,62 @@
+// RUN: clang-tblgen -gen-clang-test-pragma-attribute-supported-attributes -I%src_include_dir %src_include_dir/clang/Basic/Attr.td -o - | FileCheck %s
+
+// The number of supported attributes should never go down!
+
+// CHECK: #pragma clang attribute supports 57 attributes:
+// CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
+// CHECK-NEXT: AMDGPUWavesPerEU (SubjectMatchRule_function)
+// CHECK-NEXT: AVRSignal (SubjectMatchRule_function)
+// CHECK-NEXT: AbiTag (SubjectMatchRule_record_not_is_union, SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_namespace)
+// CHECK-NEXT: AlignValue (SubjectMatchRule_variable, SubjectMatchRule_type_alias)
+// CHECK-NEXT: AllocSize (SubjectMatchRule_function)
+// CHECK-NEXT: Annotate ()
+// CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)
+// CHECK-NEXT: CallableWhen (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Consumable (SubjectMatchRule_record)
+// CHECK-NEXT: Convergent (SubjectMatchRule_function)
+// CHECK-NEXT: DLLExport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
+// CHECK-NEXT: DLLImport (SubjectMatchRule_function, SubjectMatchRule_variable, SubjectMatchRule_record, SubjectMatchRule_objc_interface)
+// CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: EnableIf (SubjectMatchRule_function)
+// CHECK-NEXT: EnumExtensibility (SubjectMatchRule_enum)
+// CHECK-NEXT: FlagEnum (SubjectMatchRule_enum)
+// CHECK-NEXT: Flatten (SubjectMatchRule_function)
+// CHECK-NEXT: IFunc (SubjectMatchRule_function)
+// CHECK-NEXT: InternalLinkage (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record)
+// CHECK-NEXT: LTOVisibilityPublic (SubjectMatchRule_record)
+// CHECK-NEXT: NoDebug (SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter)
+// CHECK-NEXT: NoDuplicate (SubjectMatchRule_function)
+// CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: NoSplitStack (SubjectMatchRule_function)
+// CHECK-NEXT: NotTailCalled (SubjectMatchRule_function)
+// CHECK-NEXT: ObjCBoxable (SubjectMatchRule_record)
+// CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCRuntimeName (SubjectMatchRule_objc_interface, SubjectMatchRule_objc_protocol)
+// CHECK-NEXT: ObjCRuntimeVisible (SubjectMatchRule_objc_interface)
+// CHECK-NEXT: ObjCSubclassingRestricted (SubjectMatchRule_objc_interface)
+// CHECK-NEXT: OpenCLNoSVM (SubjectMatchRule_variable)
+// CHECK-NEXT: OptimizeNone (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: Overloadable (SubjectMatchRule_function)
+// CHECK-NEXT: ParamTypestate (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function)
+// CHECK-NEXT: RequireConstantInit (SubjectMatchRule_variable_is_global)
+// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
+// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: SwiftContext (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftErrorResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftIndirectResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
+// CHECK-NEXT: Target (SubjectMatchRule_function)
+// CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType)
+// CHECK-NEXT: XRayInstrument (SubjectMatchRule_function_is_member, SubjectMatchRule_objc_method, SubjectMatchRule_function)
+// CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function_is_member, SubjectMatchRule_objc_method, SubjectMatchRule_function)