[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov created this revision. slavapestov added reviewers: rjmccall, dexonsmith, aaron.ballman. Herald added a project: clang. Herald added a subscriber: cfe-commits. dexonsmith edited reviewers, added: erik.pilkington, arphaman; removed: dexonsmith. dexonsmith added a comment. +Erik and Alex, can you take a look at this? This CL lands the Clang-side support for a new Objective-C runtime feature that adds support for dynamically-allocated metadata. What follows is a basic description of this mechanism: In Swift, the class metadata contains an Objective-C class object as a prefix, followed by a vtable, generic parameters, and field offsets. If the inheritance hierarchy of a class crosses a resilience boundary, we cannot statically emit the entire metadata. Instead, it is lazily built at runtime when first needed. In order for such classes to be accessed from Clang, the Objective-C runtime will support a new mechanism whereby Swift can instead emit a "class stub" object. The class stub object is used by Clang in places where a class reference is normally emitted: - Classrefs emitted when messaging the class - Categories A class stub contains an "isa pointer" which is a scalar value 1 followed by a function pointer which realizes the real class metadata. A reference to a class stub from a classref also has its least significant pointer set to 1. The Objective-C runtime distinguishes a class stub from a real class using this fake "isa pointer". Instead of directly loading from a classref, Clang instead calls `objc_loadClassref()`; this function checks if the classref contains a class stub, and if so, it calls the function pointer and stores the result back into the classref to fast path future loads. Note that Clang already supports a objc_runtime_visible attribute. The objc_class_stub attribute can be thought of as a generalization of objc_runtime_visible. Whereas objc_runtime_visible replaces the classref load with a runtime lookup of a class by string, the class stub mechanism is more efficient because the result of the lookup is cached. Also, objc_runtime_visible does not support categories to be defined on the class, whereas objc_class_stub does. Repository: rC Clang https://reviews.llvm.org/D59628 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td lib/CodeGen/CGObjCMac.cpp lib/Sema/SemaDeclAttr.cpp test/CodeGenObjC/class-stubs.m Index: test/CodeGenObjC/class-stubs.m === --- /dev/null +++ test/CodeGenObjC/class-stubs.m @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %s | \ +// RUN: FileCheck %s + +__attribute__((objc_class_stub)) +@interface A ++ (void) classMethod; +@end + +int main() { + [A classMethod]; +} + +// CHECK-LABEL: @"OBJC_CLASSLIST_REFERENCES_$_" = private global i8* inttoptr (i64 add (i64 ptrtoint (%struct._class_t* @"OBJC_CLASS_$_A" to i64), i64 1) to i8*), section "__DATA,__objc_classrefs,regular,no_dead_strip", align 8 + + +// CHECK-LABEL: define i32 @main() +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CLASS:%.*]] = call %struct._class_t* @objc_loadClassref(i8** @"OBJC_CLASSLIST_REFERENCES_$_") +// CHECK-NEXT: [[SELECTOR:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ +// CHECK-NEXT: [[RECEIVER:%.*]] = bitcast %struct._class_t* [[CLASS]] to i8* +// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)(i8* [[RECEIVER]], i8* [[SELECTOR]]) +// CHECK-NEXT: ret i32 0 + Index: lib/Sema/SemaDeclAttr.cpp === --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -7123,6 +7123,9 @@ case ParsedAttr::AT_ObjCSubclassingRestricted: handleSimpleAttribute(S, D, AL); break; + case ParsedAttr::AT_ObjCClassStub: +handleSimpleAttribute(S, D, AL); +break; case ParsedAttr::AT_ObjCCompleteDefinition: handleSimpleAttribute(S, D, AL); break; Index: lib/CodeGen/CGObjCMac.cpp === --- lib/CodeGen/CGObjCMac.cpp +++ lib/CodeGen/CGObjCMac.cpp @@ -726,6 +726,25 @@ "objc_begin_catch"); } + /// Class objc_loadClassref (void *) + /// + /// Loads from a classref. For Objective-C stub classes, this invokes the + /// initialization callback stored inside the stub. For all other classes + /// this simply dereferences the pointer. + llvm::Constant *getLoadClassrefFn() const { +// FIXME: Other attributes? + +// Add the non-lazy-bind attribute, since objc_loadClassref is likely to +// be called a lot. +llvm::Type *params[] = { Int8PtrPtrTy }; +return CGM.CreateRuntimeFunction( +llvm::FunctionType::get(ClassnfABIPtrTy, params, false), +"objc_loadClassref", +llvm::AttributeList::get(CGM.getLLVMContext(), + llvm::At
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov marked 11 inline comments as done. slavapestov added a comment. Thanks for the comments everyone. In the next version of the patch, I fixed most of the review feedback and also addressed an issue where super message sends were not calling `objc_loadClassRef()`. Comment at: include/clang/Basic/Attr.td:1802 + let Documentation = [ObjCClassStubDocs]; +} + aaron.ballman wrote: > Does this attribute make sense outside of ObjC? e.g., should it require an > ObjC compiland? If it should only be used in ObjC, then it should have a > `LangOpts` field. The other ObjC attributes, such as ObjCSubclassingRestricted, do not have a LangOpts. Do you want me to add a LangOpts field to those too? Or is it unnecessary since they're already restricted to InterfaceDecls? Comment at: include/clang/Basic/AttrDocs.td:1116 +def ObjCClassStubDocs : Documentation { +let Category = DocCatFunction; +let Content = [{ aaron.ballman wrote: > This seems like the wrong category -- the attribute doesn't apply to > functions. Would DocCatType make more sense? Would you like me to change ObjCRuntimeVisible and a handful of other miscategorized attributes too? Comment at: lib/CodeGen/CGObjCMac.cpp:7274 +// Classrefs pointing at Objective-C stub classes have the least +// significant bit set to 1. +auto *Tag = llvm::ConstantInt::get(CGM.IntPtrTy, 1); rjmccall wrote: > This isn't for an arbitrary class ref, it's for the global class list. I'd > say something like "the global class list sets the LSB to 1 on any class > stubs". Can you explain what the difference is? My understanding is that the thing you pass to objc_loadClassref() (or load from directly) is a "classref". This is for classes you reference, not classes you define. Comment at: lib/CodeGen/CGObjCMac.cpp:7285 -Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, +Entry = new llvm::GlobalVariable(CGM.getModule(), ClassGV->getType(), false, llvm::GlobalValue::PrivateLinkage, jordan_rose wrote: > Is there a concern here in the non-stub case if GetClassGlobal no longer > produces a ObjCTypes.ClassnfABIPtrTy? (Probably not, but thought I'd check > [again].) You raise a good point. I brought back the assert in the next iteration of the patch. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov updated this revision to Diff 192378. slavapestov marked 2 inline comments as done. slavapestov added a comment. Second revision adds the following: - Validation of the attribute in Sema - Sema tests for the above - Correct behavior of super method calls of a class with the attribute - More comprehensive CodeGen tests CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/ObjCRuntime.h lib/CodeGen/CGObjCMac.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclObjC.cpp test/CodeGenObjC/class-stubs.m test/Misc/pragma-attribute-supported-attributes-list.test test/SemaObjC/class-stub-attr-unsupported.m test/SemaObjC/class-stub-attr.m Index: test/SemaObjC/class-stub-attr.m === --- /dev/null +++ test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_class_stub(123))) // expected-error {{'objc_class_stub' attribute takes no arguments}} +@interface InvalidClassStubAttribute : NSObject +@end + +__attribute__((objc_class_stub)) // expected-error {{'objc_class_stub' attribute only applies to Objective-C interfaces}} +int cannotHaveObjCClassStubAttribute() {} Index: test/SemaObjC/class-stub-attr-unsupported.m === --- /dev/null +++ test/SemaObjC/class-stub-attr-unsupported.m @@ -0,0 +1,10 @@ +// RUN: %clang -target i386-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target i386-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface StubClass : NSObject // expected-error {{'objc_class_stub' attribute is not supported for this target}} +@end Index: test/Misc/pragma-attribute-supported-attributes-list.test === --- test/Misc/pragma-attribute-supported-attributes-list.test +++ test/Misc/pragma-attribute-supported-attributes-list.test @@ -95,6 +95,7 @@ // CHECK-NEXT: ObjCBridge (SubjectMatchRule_record, SubjectMatchRule_type_alias) // CHECK-NEXT: ObjCBridgeMutable (SubjectMatchRule_record) // CHECK-NEXT: ObjCBridgeRelated (SubjectMatchRule_record) +// CHECK-NEXT: ObjCClassStub (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCCompleteDefinition (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCDesignatedInitializer (SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface) Index: test/CodeGenObjC/class-stubs.m === --- /dev/null +++ test/CodeGenObjC/class-stubs.m @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %s | \ +// RUN: FileCheck %s + +// -- classref for the message send in main() +// +// The class is declared with objc_class_stub, so LSB of the class pointer +// must be set to 1. +// +// CHECK-LABEL: @"OBJC_CLASSLIST_REFERENCES_$_" = private global i8* getelementptr (i8, i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_Base" to i8*), i32 1), section "__DATA,__objc_classrefs,regular,no_dead_strip", align 8 + +// -- classref for the super message send in anotherClassMethod() +// +// Metaclasses do not use the "stub" mechanism and are referenced statically. +// +// CHECK-LABEL: @"OBJC_CLASSLIST_SUP_REFS_$_" = private global %struct._class_t* @"OBJC_METACLASS_$_Derived", section "__DATA,__objc_superrefs,regular,no_dead_strip", align 8 + +// -- classref for the super message send in anotherInstanceMethod() +// +// The class is declared with objc_class_stub, so LSB of the class pointer +// must be set to 1. +// +// CHECK-LABEL: @"OBJC_CLASSLIST_SUP_REFS_$_.1" = private global i8* getelementptr (i8, i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_Derived" to i8*), i32 1), section "__DATA,__objc_superrefs,regular,no_dead_strip", align 8 + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov added a comment. I don't know what the etiquette is around here about pinging reviewers for a re-review, but this CL is ready for another look. Your feedback is much appreciated! CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov updated this revision to Diff 193407. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/ObjCRuntime.h lib/CodeGen/CGObjCMac.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclObjC.cpp test/CodeGenObjC/class-stubs.m test/Misc/pragma-attribute-supported-attributes-list.test test/SemaObjC/class-stub-attr-unsupported.m test/SemaObjC/class-stub-attr.m utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -1969,10 +1969,15 @@ << ", /*IsSupported=*/"; if (!LangOpts.empty()) { for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - const StringRef Part = (*I)->getValueAsString("Name"); if ((*I)->getValueAsBit("Negated")) OS << "!"; - OS << "LangOpts." << Part; + const StringRef Code = (*I)->getValueAsString("CustomCode"); + if (!Code.empty()) { +OS << Code; + } else { +const StringRef Name = (*I)->getValueAsString("Name"); +OS << "LangOpts." << Name; + } if (I + 1 != E) OS << " || "; } @@ -2957,15 +2962,15 @@ OS << "case AttrSyntax::" << Variety << ": {\n"; // C++11-style attributes are further split out based on the Scope. for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { - if (I != List.cbegin()) -OS << " else "; - if (I->first.empty()) -OS << "if (ScopeName == \"\") {\n"; - else -OS << "if (ScopeName == \"" << I->first << "\") {\n"; - OS << " return llvm::StringSwitch(Name)\n"; - GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); - OS << "}"; + if (I != List.cbegin()) +OS << " else "; + if (I->first.empty()) +OS << "if (ScopeName == \"\") {\n"; + else +OS << "if (ScopeName == \"" << I->first << "\") {\n"; + OS << " return llvm::StringSwitch(Name)\n"; + GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); + OS << "}"; } OS << "\n} break;\n"; }; @@ -3426,16 +3431,22 @@ // codegen efficiency). std::string FnName = "check", Test; for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { -const StringRef Part = (*I)->getValueAsString("Name"); if ((*I)->getValueAsBit("Negated")) { FnName += "Not"; Test += "!"; } -Test += "S.LangOpts."; -Test += Part; +const StringRef Name = (*I)->getValueAsString("Name"); +FnName += Name; +const StringRef Code = (*I)->getValueAsString("CustomCode"); +if (!Code.empty()) { + Test += "S."; + Test += Code; +} else { + Test += "S.LangOpts."; + Test += Name; +} if (I + 1 != E) Test += " || "; -FnName += Part; } FnName += "LangOpts"; Index: test/SemaObjC/class-stub-attr.m === --- /dev/null +++ test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_class_stub(123))) // expected-error {{'objc_class_stub' attribute takes no arguments}} +@interface InvalidClassStubAttribute : NSObject +@end + +__attribute__((objc_class_stub)) // expected-error {{'objc_class_stub' attribute only applies to Objective-C interfaces}} +int cannotHaveObjCClassStubAttribute() {} Index: test/SemaObjC/class-stub-attr-unsupported.m === --- /dev/null +++ test/SemaObjC/class-stub-attr-unsupported.m @@ -0,0 +1,10 @@ +// RUN: %clang -target i386-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target i386-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) // expected-warning {{'objc_class_stub' attribute ignored}} +__attribute__((objc_su
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov updated this revision to Diff 199885. slavapestov added a comment. Updated patch to address review feedback. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/ObjCRuntime.h clang/lib/CodeGen/CGObjCMac.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaDeclObjC.cpp clang/test/CodeGenObjC/class-stubs.m clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/SemaObjC/class-stub-attr-unsupported.m clang/test/SemaObjC/class-stub-attr.m clang/utils/TableGen/ClangAttrEmitter.cpp Index: clang/utils/TableGen/ClangAttrEmitter.cpp === --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1922,6 +1922,34 @@ return true; } +static std::string GenerateTestExpression(ArrayRef LangOpts) { + std::string Test; + + for (auto *E : LangOpts) { +if (!Test.empty()) + Test += " || "; + +if (E->getValueAsBit("Negated")) { + Test += "!"; +} + +const StringRef Code = E->getValueAsString("CustomCode"); +if (!Code.empty()) { + Test += "("; + Test += Code; + Test += ")"; +} else { + Test += "LangOpts."; + Test += E->getValueAsString("Name"); +} + } + + if (Test.empty()) +return "true"; + + return Test; +} + std::string PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, raw_ostream &OS) { @@ -1948,19 +1976,8 @@ // rules if the specific language options are specified. std::vector LangOpts = Rule.getLangOpts(); OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() - << ", /*IsSupported=*/"; - if (!LangOpts.empty()) { -for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - const StringRef Part = (*I)->getValueAsString("Name"); - if ((*I)->getValueAsBit("Negated")) -OS << "!"; - OS << "LangOpts." << Part; - if (I + 1 != E) -OS << " || "; -} - } else -OS << "true"; - OS << "));\n"; + << ", /*IsSupported=*/" << GenerateTestExpression(LangOpts) + << "));\n"; } } OS << "}\n\n"; @@ -3431,22 +3448,14 @@ if (LangOpts.empty()) return "defaultDiagnoseLangOpts"; - // Generate the test condition, as well as a unique function name for the - // diagnostic test. The list of options should usually be short (one or two - // options), and the uniqueness isn't strictly necessary (it is just for - // codegen efficiency). - std::string FnName = "check", Test; + // Generate a unique function name for the diagnostic test. The list of + // options should usually be short (one or two options), and the + // uniqueness isn't strictly necessary (it is just for codegen efficiency). + std::string FnName = "check"; for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { -const StringRef Part = (*I)->getValueAsString("Name"); -if ((*I)->getValueAsBit("Negated")) { +if ((*I)->getValueAsBit("Negated")) FnName += "Not"; - Test += "!"; -} -Test += "S.LangOpts."; -Test += Part; -if (I + 1 != E) - Test += " || "; -FnName += Part; +FnName += (*I)->getValueAsString("Name"); } FnName += "LangOpts"; @@ -3458,7 +3467,8 @@ return *I; OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n"; - OS << " if (" << Test << ")\n"; + OS << " auto &LangOpts = S.LangOpts;\n"; + OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; OS << "return true;\n\n"; OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; OS << "<< Attr.getName();\n"; Index: clang/test/SemaObjC/class-stub-attr.m === --- /dev/null +++ clang/test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_class_s
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov updated this revision to Diff 199905. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/ObjCRuntime.h clang/lib/CodeGen/CGObjCMac.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaDeclObjC.cpp clang/test/CodeGenObjC/class-stubs.m clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/SemaObjC/class-stub-attr-unsupported.m clang/test/SemaObjC/class-stub-attr.m clang/utils/TableGen/ClangAttrEmitter.cpp Index: clang/utils/TableGen/ClangAttrEmitter.cpp === --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1922,6 +1922,30 @@ return true; } +static std::string GenerateTestExpression(ArrayRef LangOpts) { + std::string Test; + + for (auto *E : LangOpts) { +if (!Test.empty()) + Test += " || "; + +const StringRef Code = E->getValueAsString("CustomCode"); +if (!Code.empty()) { + Test += "("; + Test += Code; + Test += ")"; +} else { + Test += "LangOpts."; + Test += E->getValueAsString("Name"); +} + } + + if (Test.empty()) +return "true"; + + return Test; +} + std::string PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, raw_ostream &OS) { @@ -1948,19 +1972,8 @@ // rules if the specific language options are specified. std::vector LangOpts = Rule.getLangOpts(); OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() - << ", /*IsSupported=*/"; - if (!LangOpts.empty()) { -for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - const StringRef Part = (*I)->getValueAsString("Name"); - if ((*I)->getValueAsBit("Negated")) -OS << "!"; - OS << "LangOpts." << Part; - if (I + 1 != E) -OS << " || "; -} - } else -OS << "true"; - OS << "));\n"; + << ", /*IsSupported=*/" << GenerateTestExpression(LangOpts) + << "));\n"; } } OS << "}\n\n"; @@ -3431,23 +3444,12 @@ if (LangOpts.empty()) return "defaultDiagnoseLangOpts"; - // Generate the test condition, as well as a unique function name for the - // diagnostic test. The list of options should usually be short (one or two - // options), and the uniqueness isn't strictly necessary (it is just for - // codegen efficiency). - std::string FnName = "check", Test; - for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { -const StringRef Part = (*I)->getValueAsString("Name"); -if ((*I)->getValueAsBit("Negated")) { - FnName += "Not"; - Test += "!"; -} -Test += "S.LangOpts."; -Test += Part; -if (I + 1 != E) - Test += " || "; -FnName += Part; - } + // Generate a unique function name for the diagnostic test. The list of + // options should usually be short (one or two options), and the + // uniqueness isn't strictly necessary (it is just for codegen efficiency). + std::string FnName = "check"; + for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) +FnName += (*I)->getValueAsString("Name"); FnName += "LangOpts"; // If this code has already been generated, simply return the previous @@ -3458,7 +3460,8 @@ return *I; OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n"; - OS << " if (" << Test << ")\n"; + OS << " auto &LangOpts = S.LangOpts;\n"; + OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; OS << "return true;\n\n"; OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; OS << "<< Attr.getName();\n"; Index: clang/test/SemaObjC/class-stub-attr.m === --- /dev/null +++ clang/test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_class_stub(123))) // expected-error {{'objc_clas
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov updated this revision to Diff 200808. slavapestov marked 6 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/ObjCRuntime.h clang/lib/CodeGen/CGObjCMac.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaDeclObjC.cpp clang/test/CodeGenObjC/class-stubs.m clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/SemaObjC/class-stub-attr-unsupported.m clang/test/SemaObjC/class-stub-attr.m clang/utils/TableGen/ClangAttrEmitter.cpp Index: clang/utils/TableGen/ClangAttrEmitter.cpp === --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1922,6 +1922,30 @@ return true; } +static std::string GenerateTestExpression(ArrayRef LangOpts) { + std::string Test; + + for (auto *E : LangOpts) { +if (!Test.empty()) + Test += " || "; + +const StringRef Code = E->getValueAsString("CustomCode"); +if (!Code.empty()) { + Test += "("; + Test += Code; + Test += ")"; +} else { + Test += "LangOpts."; + Test += E->getValueAsString("Name"); +} + } + + if (Test.empty()) +return "true"; + + return Test; +} + std::string PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, raw_ostream &OS) { @@ -1948,19 +1972,8 @@ // rules if the specific language options are specified. std::vector LangOpts = Rule.getLangOpts(); OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() - << ", /*IsSupported=*/"; - if (!LangOpts.empty()) { -for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - const StringRef Part = (*I)->getValueAsString("Name"); - if ((*I)->getValueAsBit("Negated")) -OS << "!"; - OS << "LangOpts." << Part; - if (I + 1 != E) -OS << " || "; -} - } else -OS << "true"; - OS << "));\n"; + << ", /*IsSupported=*/" << GenerateTestExpression(LangOpts) + << "));\n"; } } OS << "}\n\n"; @@ -3431,23 +3444,12 @@ if (LangOpts.empty()) return "defaultDiagnoseLangOpts"; - // Generate the test condition, as well as a unique function name for the - // diagnostic test. The list of options should usually be short (one or two - // options), and the uniqueness isn't strictly necessary (it is just for - // codegen efficiency). - std::string FnName = "check", Test; - for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { -const StringRef Part = (*I)->getValueAsString("Name"); -if ((*I)->getValueAsBit("Negated")) { - FnName += "Not"; - Test += "!"; -} -Test += "S.LangOpts."; -Test += Part; -if (I + 1 != E) - Test += " || "; -FnName += Part; - } + // Generate a unique function name for the diagnostic test. The list of + // options should usually be short (one or two options), and the + // uniqueness isn't strictly necessary (it is just for codegen efficiency). + std::string FnName = "check"; + for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) +FnName += (*I)->getValueAsString("Name"); FnName += "LangOpts"; // If this code has already been generated, simply return the previous @@ -3458,7 +3460,8 @@ return *I; OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n"; - OS << " if (" << Test << ")\n"; + OS << " auto &LangOpts = S.LangOpts;\n"; + OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; OS << "return true;\n\n"; OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; OS << "<< Attr.getName();\n"; Index: clang/test/SemaObjC/class-stub-attr.m === --- /dev/null +++ clang/test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_cl
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov updated this revision to Diff 202084. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/ObjCRuntime.h clang/lib/CodeGen/CGObjCMac.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaDeclObjC.cpp clang/test/CodeGenObjC/class-stubs.m clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/SemaObjC/class-stub-attr-unsupported.m clang/test/SemaObjC/class-stub-attr.m clang/utils/TableGen/ClangAttrEmitter.cpp Index: clang/utils/TableGen/ClangAttrEmitter.cpp === --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1922,6 +1922,30 @@ return true; } +static std::string GenerateTestExpression(ArrayRef LangOpts) { + std::string Test; + + for (auto *E : LangOpts) { +if (!Test.empty()) + Test += " || "; + +const StringRef Code = E->getValueAsString("CustomCode"); +if (!Code.empty()) { + Test += "("; + Test += Code; + Test += ")"; +} else { + Test += "LangOpts."; + Test += E->getValueAsString("Name"); +} + } + + if (Test.empty()) +return "true"; + + return Test; +} + std::string PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, raw_ostream &OS) { @@ -1948,19 +1972,8 @@ // rules if the specific language options are specified. std::vector LangOpts = Rule.getLangOpts(); OS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue() - << ", /*IsSupported=*/"; - if (!LangOpts.empty()) { -for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { - const StringRef Part = (*I)->getValueAsString("Name"); - if ((*I)->getValueAsBit("Negated")) -OS << "!"; - OS << "LangOpts." << Part; - if (I + 1 != E) -OS << " || "; -} - } else -OS << "true"; - OS << "));\n"; + << ", /*IsSupported=*/" << GenerateTestExpression(LangOpts) + << "));\n"; } } OS << "}\n\n"; @@ -3431,23 +3444,12 @@ if (LangOpts.empty()) return "defaultDiagnoseLangOpts"; - // Generate the test condition, as well as a unique function name for the - // diagnostic test. The list of options should usually be short (one or two - // options), and the uniqueness isn't strictly necessary (it is just for - // codegen efficiency). - std::string FnName = "check", Test; - for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { -const StringRef Part = (*I)->getValueAsString("Name"); -if ((*I)->getValueAsBit("Negated")) { - FnName += "Not"; - Test += "!"; -} -Test += "S.LangOpts."; -Test += Part; -if (I + 1 != E) - Test += " || "; -FnName += Part; - } + // Generate a unique function name for the diagnostic test. The list of + // options should usually be short (one or two options), and the + // uniqueness isn't strictly necessary (it is just for codegen efficiency). + std::string FnName = "check"; + for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) +FnName += (*I)->getValueAsString("Name"); FnName += "LangOpts"; // If this code has already been generated, simply return the previous @@ -3458,7 +3460,8 @@ return *I; OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n"; - OS << " if (" << Test << ")\n"; + OS << " auto &LangOpts = S.LangOpts;\n"; + OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; OS << "return true;\n\n"; OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; OS << "<< Attr.getName();\n"; Index: clang/test/SemaObjC/class-stub-attr.m === --- /dev/null +++ clang/test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_class_stub(123))) // expected-error {{'objc_clas
[PATCH] D59628: Add support for __attribute__((objc_class_stub))
slavapestov marked 2 inline comments as done. slavapestov added inline comments. Comment at: clang/include/clang/Basic/Attr.td:297 def CUDA : LangOpt<"CUDA">; -def COnly : LangOpt<"CPlusPlus", 1>; +def COnly : LangOpt<"COnly", "!LangOpts.CPlusPlus">; def CPlusPlus : LangOpt<"CPlusPlus">; aaron.ballman wrote: > This compiles? I would have assumed that it would have to be `def COnly : > LangOpt<"COnly", [{!LangOpts.CPlusPlus}]>;` > > (If it compiles as-is, that's fine, I just wasn't aware that you could use > string syntax for code blocks.) It appears that both work! Going with your suggested version. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59628/new/ https://reviews.llvm.org/D59628 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits