diff options
author | John McCall <rjmccall@apple.com> | 2019-05-30 04:09:01 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2019-05-30 04:09:01 +0000 |
commit | 2c91c3b7af7cd4da64f1babde3798d65522a21e4 (patch) | |
tree | 0be9af0287a5fa41bb097a1bae0d3fa0a8626e07 /clang/utils/TableGen/ClangAttrEmitter.cpp | |
parent | 1f67d9427931f61585d2392c3b958cd2b459af54 (diff) | |
download | bcm5719-llvm-2c91c3b7af7cd4da64f1babde3798d65522a21e4.tar.gz bcm5719-llvm-2c91c3b7af7cd4da64f1babde3798d65522a21e4.zip |
Add the `objc_class_stub` attribute.
Swift requires certain classes to be not just initialized lazily on first
use, but actually allocated lazily using information that is only available
at runtime. This is incompatible with ObjC class initialization, or at least
not efficiently compatible, because there is no meaningful class symbol
that can be put in a class-ref variable at load time. This leaves ObjC
code unable to access such classes, which is undesirable.
objc_class_stub says that class references should be resolved by calling
a new ObjC runtime function with a pointer to a new "class stub" structure.
Non-ObjC compilers (like Swift) can simply emit this structure when ObjC
interop is required for a class that cannot be statically allocated,
then apply this attribute to the `@interface` in the generated ObjC header
for the class.
This attribute can be thought of as a generalization of the existing
`objc_runtime_visible` attribute which permits more efficient class
resolution as well as supporting the additon of categories to the class.
Subclassing these classes from ObjC is currently not allowed.
Patch by Slava Pestov!
llvm-svn: 362054
Diffstat (limited to 'clang/utils/TableGen/ClangAttrEmitter.cpp')
-rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 65 |
1 files changed, 34 insertions, 31 deletions
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 077bfe48ab3..a32d80557e6 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1922,6 +1922,30 @@ bool PragmaClangAttributeSupport::isAttributedSupported( return true; } +static std::string GenerateTestExpression(ArrayRef<Record *> 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 @@ PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, // rules if the specific language options are specified. std::vector<Record *> 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 @@ static std::string GenerateLangOptRequirements(const Record &R, 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 @@ static std::string GenerateLangOptRequirements(const Record &R, 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"; |