diff options
| author | John McCall <rjmccall@apple.com> | 2012-06-20 06:18:46 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2012-06-20 06:18:46 +0000 |
| commit | 5fb5df9c8385c3c86fe3d31fbac5766217168a9b (patch) | |
| tree | d0aa1ee58ae92997f1aa7af1556fb7cda32f3173 /clang/lib | |
| parent | b9e8e189497ef4a690c913b09ce6a8ff03281c60 (diff) | |
| download | bcm5719-llvm-5fb5df9c8385c3c86fe3d31fbac5766217168a9b.tar.gz bcm5719-llvm-5fb5df9c8385c3c86fe3d31fbac5766217168a9b.zip | |
Restructure how the driver communicates information about the
target Objective-C runtime down to the frontend: break this
down into a single target runtime kind and version, and compute
all the relevant information from that. This makes it
relatively painless to add support for new runtimes to the
compiler. Make the new -cc1 flag, -fobjc-runtime=blah-x.y.z,
available at the driver level as a better and more general
alternative to -fgnu-runtime and -fnext-runtime. This new
concept of an Objective-C runtime also encompasses what we
were previously separating out as the "Objective-C ABI", so
fragile vs. non-fragile runtimes are now really modelled as
different kinds of runtime, paving the way for better overall
differentiation.
As a sort of special case, continue to accept the -cc1 flag
-fobjc-runtime-has-weak, as a sop to PLCompatibilityWeak.
I won't go so far as to say "no functionality change", even
ignoring the new driver flag, but subtle changes in driver
semantics are almost certainly not intended.
llvm-svn: 158793
Diffstat (limited to 'clang/lib')
29 files changed, 474 insertions, 279 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index d8677c2ee1b..9f8578bafe3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4484,7 +4484,7 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, // information is not especially sensible, but we're stuck with it for // compatibility with GCC, although providing it breaks anything that // actually uses runtime introspection and wants to work on both runtimes... - if (!Ctx->getLangOpts().NeXTRuntime) { + if (Ctx->getLangOpts().ObjCRuntime.isGNUFamily()) { const RecordDecl *RD = FD->getParent(); const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex())); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index de971730897..7d720937004 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -411,23 +411,32 @@ AvailabilityResult Decl::getAvailability(std::string *Message) const { bool Decl::canBeWeakImported(bool &IsDefinition) const { IsDefinition = false; + + // Variables, if they aren't definitions. if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { if (!Var->hasExternalStorage() || Var->getInit()) { IsDefinition = true; return false; } + return true; + + // Functions, if they aren't definitions. } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { if (FD->hasBody()) { IsDefinition = true; return false; } - } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this)) - return false; - else if (!(getASTContext().getLangOpts().ObjCNonFragileABI && - isa<ObjCInterfaceDecl>(this))) - return false; + return true; - return true; + // Objective-C classes, if this is the non-fragile runtime. + } else if (isa<ObjCInterfaceDecl>(this) && + getASTContext().getLangOpts().ObjCRuntime.isNonFragile()) { + return true; + + // Nothing else. + } else { + return false; + } } bool Decl::isWeakImported() const { diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index ef2e93c49cd..ff661fd70bd 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangBasic IdentifierTable.cpp LangOptions.cpp Module.cpp + ObjCRuntime.cpp SourceLocation.cpp SourceManager.cpp TargetInfo.cpp diff --git a/clang/lib/Basic/ObjCRuntime.cpp b/clang/lib/Basic/ObjCRuntime.cpp new file mode 100644 index 00000000000..d92adbcb461 --- /dev/null +++ b/clang/lib/Basic/ObjCRuntime.cpp @@ -0,0 +1,79 @@ +//===- ObjCRuntime.cpp - Objective-C Runtime Handling -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ObjCRuntime class, which represents the +// target Objective-C runtime. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/ObjCRuntime.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +std::string ObjCRuntime::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +raw_ostream &clang::operator<<(raw_ostream &out, const ObjCRuntime &value) { + switch (value.getKind()) { + case ObjCRuntime::MacOSX: out << "macosx"; break; + case ObjCRuntime::FragileMacOSX: out << "macosx-fragile"; break; + case ObjCRuntime::iOS: out << "ios"; break; + case ObjCRuntime::GNU: out << "gnu"; break; + case ObjCRuntime::FragileGNU: out << "gnu-fragile"; break; + } + if (value.getVersion() > VersionTuple(0)) { + out << '-' << value.getVersion(); + } + return out; +} + +bool ObjCRuntime::tryParse(StringRef input) { + // Look for the last dash. + std::size_t dash = input.rfind('-'); + + // We permit (1) dashes in the runtime name and (2) the version to + // be omitted, so ignore dashes that aren't followed by a digit. + if (dash != StringRef::npos && dash + 1 != input.size() && + (input[dash+1] < '0' || input[dash+1] > '9')) { + dash = StringRef::npos; + } + + // Everything prior to that must be a valid string name. + Kind kind; + StringRef runtimeName = input.substr(0, dash); + if (runtimeName == "macosx") { + kind = ObjCRuntime::MacOSX; + } else if (runtimeName == "macosx-fragile") { + kind = ObjCRuntime::FragileMacOSX; + } else if (runtimeName == "ios") { + kind = ObjCRuntime::iOS; + } else if (runtimeName == "gnu") { + kind = ObjCRuntime::GNU; + } else if (runtimeName == "gnu-fragile") { + kind = ObjCRuntime::FragileGNU; + } else { + return true; + } + TheKind = kind; + + Version = VersionTuple(0); + if (dash != StringRef::npos) { + StringRef verString = input.substr(dash + 1); + if (Version.tryParse(verString)) + return true; + } + + return false; +} diff --git a/clang/lib/Basic/VersionTuple.cpp b/clang/lib/Basic/VersionTuple.cpp index 77aad39cbf2..4f479d00d6c 100644 --- a/clang/lib/Basic/VersionTuple.cpp +++ b/clang/lib/Basic/VersionTuple.cpp @@ -34,3 +34,55 @@ raw_ostream& clang::operator<<(raw_ostream &Out, Out << '.' << *Subminor; return Out; } + +static bool parseInt(StringRef &input, unsigned &value) { + assert(value == 0); + if (input.empty()) return true; + + char next = input[0]; + input = input.substr(1); + if (next < '0' || next > '9') return true; + value = (unsigned) (next - '0'); + + while (!input.empty()) { + next = input[0]; + if (next < '0' || next > '9') return false; + input = input.substr(1); + value = value * 10 + (unsigned) (next - '0'); + } + + return false; +} + +bool VersionTuple::tryParse(StringRef input) { + unsigned major = 0, minor = 0, micro = 0; + + // Parse the major version, [0-9]+ + if (parseInt(input, major)) return true; + + if (input.empty()) { + *this = VersionTuple(major); + return false; + } + + // If we're not done, parse the minor version, \.[0-9]+ + if (input[0] != '.') return true; + input = input.substr(1); + if (parseInt(input, minor)) return true; + + if (input.empty()) { + *this = VersionTuple(major, minor); + return false; + } + + // If we're not done, parse the micro version, \.[0-9]+ + if (input[0] != '.') return true; + input = input.substr(1); + if (parseInt(input, micro)) return true; + + // If we have characters left over, it's an error. + if (!input.empty()) return true; + + *this = VersionTuple(major, minor, micro); + return false; +} diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 2deff030ab4..19ea18c4cbc 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -320,7 +320,7 @@ void CGDebugInfo::CreateCompileUnit() { // Figure out which version of the ObjC runtime we have. unsigned RuntimeVers = 0; if (LO.ObjC1) - RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1; + RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1; // Create new compile unit. DBuilder.createCompileUnit( @@ -1390,8 +1390,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // the non-fragile abi and the debugger should ignore the value anyways. // Call it the FieldNo+1 due to how debuggers use the information, // e.g. negating the value when it needs a lookup in the dynamic table. - uint64_t FieldOffset = CGM.getLangOpts().ObjCNonFragileABI ? FieldNo+1 - : RL.getFieldOffset(FieldNo); + uint64_t FieldOffset = CGM.getLangOpts().ObjCRuntime.isNonFragile() + ? FieldNo+1 : RL.getFieldOffset(FieldNo); unsigned Flags = 0; if (Field->getAccessControl() == ObjCIvarDecl::Protected) diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 4cf7f12bd61..fb36715364b 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -126,7 +126,7 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { if (CGF.getLangOpts().CPlusPlus) name = "_ZSt9terminatev"; // FIXME: mangling! else if (CGF.getLangOpts().ObjC1 && - CGF.CGM.getCodeGenOpts().ObjCRuntimeHasTerminate) + CGF.getLangOpts().ObjCRuntime.hasTerminate()) name = "objc_terminate"; else name = "abort"; @@ -180,12 +180,17 @@ static const EHPersonality &getCPersonality(const LangOptions &L) { } static const EHPersonality &getObjCPersonality(const LangOptions &L) { - if (L.NeXTRuntime) { - if (L.ObjCNonFragileABI) return EHPersonality::NeXT_ObjC; - else return getCPersonality(L); - } else { + switch (L.ObjCRuntime.getKind()) { + case ObjCRuntime::FragileMacOSX: + return getCPersonality(L); + case ObjCRuntime::MacOSX: + case ObjCRuntime::iOS: + return EHPersonality::NeXT_ObjC; + case ObjCRuntime::GNU: + case ObjCRuntime::FragileGNU: return EHPersonality::GNU_ObjC; } + llvm_unreachable("bad runtime kind"); } static const EHPersonality &getCXXPersonality(const LangOptions &L) { @@ -198,22 +203,26 @@ static const EHPersonality &getCXXPersonality(const LangOptions &L) { /// Determines the personality function to use when both C++ /// and Objective-C exceptions are being caught. static const EHPersonality &getObjCXXPersonality(const LangOptions &L) { + switch (L.ObjCRuntime.getKind()) { // The ObjC personality defers to the C++ personality for non-ObjC // handlers. Unlike the C++ case, we use the same personality // function on targets using (backend-driven) SJLJ EH. - if (L.NeXTRuntime) { - if (L.ObjCNonFragileABI) - return EHPersonality::NeXT_ObjC; + case ObjCRuntime::MacOSX: + case ObjCRuntime::iOS: + return EHPersonality::NeXT_ObjC; - // In the fragile ABI, just use C++ exception handling and hope - // they're not doing crazy exception mixing. - else - return getCXXPersonality(L); - } + // In the fragile ABI, just use C++ exception handling and hope + // they're not doing crazy exception mixing. + case ObjCRuntime::FragileMacOSX: + return getCXXPersonality(L); // The GNU runtime's personality function inherently doesn't support // mixed EH. Use the C++ personality just to avoid returning null. - return EHPersonality::GNU_ObjCXX; + case ObjCRuntime::GNU: + case ObjCRuntime::FragileGNU: + return EHPersonality::GNU_ObjCXX; + } + llvm_unreachable("bad runtime kind"); } const EHPersonality &EHPersonality::get(const LangOptions &L) { diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index f1047bd3b9a..b62dffc2552 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1690,9 +1690,10 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, StringRef fnName) { llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName); - // In -fobjc-no-arc-runtime, emit weak references to the runtime - // support library. - if (!CGM.getCodeGenOpts().ObjCRuntimeHasARC) + // If the target runtime doesn't naturally support ARC, emit weak + // references to the runtime support library. We don't really + // permit this to fail, but we need a particular relocation style. + if (!CGM.getLangOpts().ObjCRuntime.hasARC()) if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) f->setLinkage(llvm::Function::ExternalWeakLinkage); @@ -2722,7 +2723,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt( // Keep track of the current cleanup stack depth. RunCleanupsScope Scope(*this); - if (CGM.getCodeGenOpts().ObjCRuntimeHasARC) { + if (CGM.getLangOpts().ObjCRuntime.hasARC()) { llvm::Value *token = EmitObjCAutoreleasePoolPush(); EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token); } else { @@ -2754,6 +2755,11 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) { Builder.CreateCall(extender, object)->setDoesNotThrow(); } +static bool hasAtomicCopyHelperAPI(const ObjCRuntime &runtime) { + // For now, only NeXT has these APIs. + return runtime.isNeXTFamily(); +} + /// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with /// non-trivial copy assignment function, produce following helper function. /// static void copyHelper(Ty *dest, const Ty *source) { *dest = *source; } @@ -2762,7 +2768,8 @@ llvm::Constant * CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( const ObjCPropertyImplDecl *PID) { // FIXME. This api is for NeXt runtime only for now. - if (!getLangOpts().CPlusPlus || !getLangOpts().NeXTRuntime) + if (!getLangOpts().CPlusPlus || + !hasAtomicCopyHelperAPI(getLangOpts().ObjCRuntime)) return 0; QualType Ty = PID->getPropertyIvarDecl()->getType(); if (!Ty->isRecordType()) @@ -2846,7 +2853,8 @@ llvm::Constant * CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( const ObjCPropertyImplDecl *PID) { // FIXME. This api is for NeXt runtime only for now. - if (!getLangOpts().CPlusPlus || !getLangOpts().NeXTRuntime) + if (!getLangOpts().CPlusPlus || + !hasAtomicCopyHelperAPI(getLangOpts().ObjCRuntime)) return 0; const ObjCPropertyDecl *PD = PID->getPropertyDecl(); QualType Ty = PD->getType(); diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index e5935117a97..a949436e859 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -889,7 +889,7 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) { // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as // a pointer indicating object catchalls, and NULL to indicate real // catchalls - if (CGM.getLangOpts().ObjCNonFragileABI) { + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { return MakeConstantString("@id"); } else { return 0; @@ -1984,7 +1984,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); // For non-fragile ivars, set the instance size to 0 - {the size of just this // class}. The runtime will then set this to the correct value on load. - if (CGM.getContext().getLangOpts().ObjCNonFragileABI) { + if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) { instanceSize = 0 - (instanceSize - superInstanceSize); } @@ -1999,7 +1999,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { // Get the offset uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; - if (CGM.getContext().getLangOpts().ObjCNonFragileABI) { + if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) { Offset = BaseOffset - superInstanceSize; } llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); @@ -2640,7 +2640,7 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { - if (CGM.getLangOpts().ObjCNonFragileABI) { + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar); if (RuntimeVersion < 10) return CGF.Builder.CreateZExtOrBitCast( @@ -2665,7 +2665,17 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, CGObjCRuntime * clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) { - if (CGM.getLangOpts().ObjCNonFragileABI) + switch (CGM.getLangOpts().ObjCRuntime.getKind()) { + case ObjCRuntime::GNU: return new CGObjCGNUstep(CGM); - return new CGObjCGCC(CGM); + + case ObjCRuntime::FragileGNU: + return new CGObjCGCC(CGM); + + case ObjCRuntime::FragileMacOSX: + case ObjCRuntime::MacOSX: + case ObjCRuntime::iOS: + llvm_unreachable("these runtimes are not GNU runtimes"); + } + llvm_unreachable("bad runtime"); } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 9a90995ba60..3eb5d5291dc 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -6381,7 +6381,17 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, CodeGen::CGObjCRuntime * CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) { - if (CGM.getLangOpts().ObjCNonFragileABI) - return new CGObjCNonFragileABIMac(CGM); + switch (CGM.getLangOpts().ObjCRuntime.getKind()) { + case ObjCRuntime::FragileMacOSX: return new CGObjCMac(CGM); + + case ObjCRuntime::MacOSX: + case ObjCRuntime::iOS: + return new CGObjCNonFragileABIMac(CGM); + + case ObjCRuntime::GNU: + case ObjCRuntime::FragileGNU: + llvm_unreachable("these runtimes are not Mac runtimes"); + } + llvm_unreachable("bad runtime"); } diff --git a/clang/lib/CodeGen/CGRTTI.cpp b/clang/lib/CodeGen/CGRTTI.cpp index 19973b46b7c..d1b370a1f72 100644 --- a/clang/lib/CodeGen/CGRTTI.cpp +++ b/clang/lib/CodeGen/CGRTTI.cpp @@ -985,7 +985,8 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, if (!ForEH && !getContext().getLangOpts().RTTI) return llvm::Constant::getNullValue(Int8PtrTy); - if (ForEH && Ty->isObjCObjectPointerType() && !LangOpts.NeXTRuntime) + if (ForEH && Ty->isObjCObjectPointerType() && + LangOpts.ObjCRuntime.isGNUFamily()) return ObjCRuntime->GetEHType(Ty); return RTTIBuilder(*this).BuildTypeInfo(Ty); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c72b8665f35..43d573689c9 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -135,10 +135,21 @@ CodeGenModule::~CodeGenModule() { } void CodeGenModule::createObjCRuntime() { - if (!LangOpts.NeXTRuntime) + // This is just isGNUFamily(), but we want to force implementors of + // new ABIs to decide how best to do this. + switch (LangOpts.ObjCRuntime.getKind()) { + case ObjCRuntime::GNU: + case ObjCRuntime::FragileGNU: ObjCRuntime = CreateGNUObjCRuntime(*this); - else + return; + + case ObjCRuntime::FragileMacOSX: + case ObjCRuntime::MacOSX: + case ObjCRuntime::iOS: ObjCRuntime = CreateMacObjCRuntime(*this); + return; + } + llvm_unreachable("bad runtime kind"); } void CodeGenModule::createOpenCLRuntime() { @@ -494,7 +505,7 @@ static bool hasUnwindExceptions(const LangOptions &LangOpts) { // If ObjC exceptions are enabled, this depends on the ABI. if (LangOpts.ObjCExceptions) { - if (!LangOpts.ObjCNonFragileABI) return false; + if (LangOpts.ObjCRuntime.isFragile()) return false; } return true; @@ -2082,7 +2093,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { std::string StringClass(getLangOpts().ObjCConstantStringClass); llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); llvm::Constant *GV; - if (LangOpts.ObjCNonFragileABI) { + if (LangOpts.ObjCRuntime.isNonFragile()) { std::string str = StringClass.empty() ? "OBJC_CLASS_$_NSConstantString" : "OBJC_CLASS_$_" + StringClass; @@ -2170,7 +2181,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { "_unnamed_nsstring_"); // FIXME. Fix section. if (const char *Sect = - LangOpts.ObjCNonFragileABI + LangOpts.ObjCRuntime.isNonFragile() ? getContext().getTargetInfo().getNSStringNonFragileABISection() : getContext().getTargetInfo().getNSStringSection()) GV->setSection(Sect); @@ -2553,7 +2564,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::ObjCImplementation: { ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D); - if (LangOpts.ObjCNonFragileABI2 && OMD->hasSynthBitfield()) + if (LangOpts.ObjCRuntime.isNonFragile() && OMD->hasSynthBitfield()) Context.ResetObjCLayout(OMD->getClassInterface()); EmitObjCPropertyImplementations(OMD); EmitObjCIvarInitializations(OMD); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 2e3523cf1de..21aefb64397 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -14,10 +14,10 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "clang/Basic/ObjCRuntime.h" using namespace clang::driver; using namespace clang; @@ -49,25 +49,9 @@ bool ToolChain::HasNativeLLVMSupport() const { return false; } -void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const { - switch (runtime.getKind()) { - case ObjCRuntime::NeXT: - // Assume a minimal NeXT runtime. - runtime.HasARC = false; - runtime.HasWeak = false; - runtime.HasSubscripting = false; - runtime.HasTerminate = false; - return; - - case ObjCRuntime::GNU: - // Assume a maximal GNU runtime. - runtime.HasARC = true; - runtime.HasWeak = true; - runtime.HasSubscripting = false; // to be added - runtime.HasTerminate = false; // to be added - return; - } - llvm_unreachable("invalid runtime kind!"); +ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const { + return ObjCRuntime(isNonFragile ? ObjCRuntime::GNU : ObjCRuntime::FragileGNU, + VersionTuple()); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp index 7c75583eea0..1a0cd939ddc 100644 --- a/clang/lib/Driver/ToolChains.cpp +++ b/clang/lib/Driver/ToolChains.cpp @@ -14,10 +14,10 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" +#include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" #include "llvm/ADT/SmallString.h" @@ -42,9 +42,7 @@ using namespace clang; /// Darwin - Darwin tool chain for i386 and x86_64. Darwin::Darwin(const Driver &D, const llvm::Triple& Triple) - : ToolChain(D, Triple), TargetInitialized(false), - ARCRuntimeForSimulator(ARCSimulator_None), - LibCXXForSimulator(LibCXXSimulator_None) + : ToolChain(D, Triple), TargetInitialized(false) { // Compute the initial Darwin version from the triple unsigned Major, Minor, Micro; @@ -80,42 +78,19 @@ bool Darwin::HasNativeLLVMSupport() const { return true; } -bool Darwin::hasARCRuntime() const { - // FIXME: Remove this once there is a proper way to detect an ARC runtime - // for the simulator. - switch (ARCRuntimeForSimulator) { - case ARCSimulator_None: - break; - case ARCSimulator_HasARCRuntime: - return true; - case ARCSimulator_NoARCRuntime: - return false; - } - - if (isTargetIPhoneOS()) - return !isIPhoneOSVersionLT(5); - else - return !isMacosxVersionLT(10, 7); -} - -bool Darwin::hasSubscriptingRuntime() const { - return !isTargetIPhoneOS() && !isMacosxVersionLT(10, 8); -} - /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. -void Darwin::configureObjCRuntime(ObjCRuntime &runtime) const { - if (runtime.getKind() != ObjCRuntime::NeXT) - return ToolChain::configureObjCRuntime(runtime); - - runtime.HasARC = runtime.HasWeak = hasARCRuntime(); - runtime.HasSubscripting = hasSubscriptingRuntime(); - - // So far, objc_terminate is only available in iOS 5. - // FIXME: do the simulator logic properly. - if (!ARCRuntimeForSimulator && isTargetIPhoneOS()) - runtime.HasTerminate = !isIPhoneOSVersionLT(5); - else - runtime.HasTerminate = false; +ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { + if (isTargetIPhoneOS()) { + return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); + } else if (TargetSimulatorVersionFromDefines != VersionTuple()) { + return ObjCRuntime(ObjCRuntime::iOS, TargetSimulatorVersionFromDefines); + } else { + if (isNonFragile) { + return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); + } else { + return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); + } + } } /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. @@ -313,7 +288,7 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, else if (isTargetIPhoneOS()) s += "iphoneos"; // FIXME: Remove this once we depend fully on -mios-simulator-version-min. - else if (ARCRuntimeForSimulator != ARCSimulator_None) + else if (TargetSimulatorVersionFromDefines != VersionTuple()) s += "iphonesimulator"; else s += "macosx"; @@ -484,10 +459,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { unsigned Major = 0, Minor = 0, Micro = 0; if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && Major < 10 && Minor < 100 && Micro < 100) { - ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime - : ARCSimulator_HasARCRuntime; - LibCXXForSimulator = Major < 5 ? LibCXXSimulator_NotAvailable - : LibCXXSimulator_Available; + TargetSimulatorVersionFromDefines = VersionTuple(Major, Minor, Micro); } break; } @@ -901,22 +873,19 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); if (Type == ToolChain::CST_Libcxx) { - switch (LibCXXForSimulator) { - case LibCXXSimulator_None: - // Handle non-simulator cases. - if (isTargetIPhoneOS()) { - if (isIPhoneOSVersionLT(5, 0)) { - getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) - << "iOS 5.0"; - } - } - break; - case LibCXXSimulator_NotAvailable: + // Check whether the target provides libc++. + StringRef where; + + // Complain about targetting iOS < 5.0 in any way. + if ((TargetSimulatorVersionFromDefines != VersionTuple() && + TargetSimulatorVersionFromDefines < VersionTuple(5, 0)) || + (isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))) { + where = "iOS 5.0"; + } + + if (where != StringRef()) { getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) - << "iOS 5.0"; - break; - case LibCXXSimulator_Available: - break; + << where; } } diff --git a/clang/lib/Driver/ToolChains.h b/clang/lib/Driver/ToolChains.h index 3fdcba04ddf..dce3b6d8e90 100644 --- a/clang/lib/Driver/ToolChains.h +++ b/clang/lib/Driver/ToolChains.h @@ -176,22 +176,6 @@ private: // the argument translation business. mutable bool TargetInitialized; - // FIXME: Remove this once there is a proper way to detect an ARC runtime - // for the simulator. - public: - mutable enum { - ARCSimulator_None, - ARCSimulator_HasARCRuntime, - ARCSimulator_NoARCRuntime - } ARCRuntimeForSimulator; - - mutable enum { - LibCXXSimulator_None, - LibCXXSimulator_NotAvailable, - LibCXXSimulator_Available - } LibCXXForSimulator; - -private: /// Whether we are targeting iPhoneOS target. mutable bool TargetIsIPhoneOS; @@ -201,6 +185,12 @@ private: /// The OS version we are targeting. mutable VersionTuple TargetVersion; +protected: + // FIXME: Remove this once there is a proper way to detect an ARC runtime + // for the simulator. + mutable VersionTuple TargetSimulatorVersionFromDefines; + +private: /// The default macosx-version-min of this tool chain; empty until /// initialized. std::string MacosxVersionMin; @@ -209,9 +199,6 @@ private: /// initialized. std::string iOSVersionMin; - bool hasARCRuntime() const; - bool hasSubscriptingRuntime() const; - private: void AddDeploymentTarget(DerivedArgList &Args) const; @@ -258,7 +245,7 @@ public: bool isTargetMacOS() const { return !isTargetIOSSimulator() && !isTargetIPhoneOS() && - ARCRuntimeForSimulator == ARCSimulator_None; + TargetSimulatorVersionFromDefines == VersionTuple(); } bool isTargetInitialized() const { return TargetInitialized; } @@ -300,7 +287,7 @@ public: virtual bool HasNativeLLVMSupport() const; - virtual void configureObjCRuntime(ObjCRuntime &runtime) const; + virtual ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const; virtual bool hasBlocksRuntime() const; virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 1669fd515d3..aff96888184 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -16,11 +16,11 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Job.h" -#include "clang/Driver/ObjCRuntime.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" +#include "clang/Basic/ObjCRuntime.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -1187,13 +1187,12 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, } static bool -shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion, +shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { // We use the zero-cost exception tables for Objective-C if the non-fragile // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and // later. - - if (objcABIVersion >= 2) + if (runtime.isNonFragile()) return true; if (!Triple.isOSDarwin()) @@ -1212,7 +1211,7 @@ shouldUseExceptionTablesForObjCExceptions(unsigned objcABIVersion, static void addExceptionArgs(const ArgList &Args, types::ID InputType, const llvm::Triple &Triple, bool KernelOrKext, - unsigned objcABIVersion, + const ObjCRuntime &objcRuntime, ArgStringList &CmdArgs) { if (KernelOrKext) { // -mkernel and -fapple-kext imply no exceptions, so claim exception related @@ -1258,7 +1257,7 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fobjc-exceptions"); ShouldUseExceptionTables |= - shouldUseExceptionTablesForObjCExceptions(objcABIVersion, Triple); + shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple); } if (types::isCXX(InputType)) { @@ -1444,8 +1443,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Select the appropriate action. - bool IsRewriter = false; - bool IsModernRewriter = false; + RewriteKind rewriteKind = RK_None; if (isa<AnalyzeJobAction>(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); @@ -1517,10 +1515,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-pch"); } else if (JA.getType() == types::TY_RewrittenObjC) { CmdArgs.push_back("-rewrite-objc"); - IsModernRewriter = true; + rewriteKind = RK_NonFragile; } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { CmdArgs.push_back("-rewrite-objc"); - IsRewriter = true; + rewriteKind = RK_Fragile; } else { assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); @@ -2442,80 +2440,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fno_inline_functions)) CmdArgs.push_back("-fno-inline-functions"); - // -fobjc-nonfragile-abi=0 is default. - ObjCRuntime objCRuntime; - unsigned objcABIVersion = 0; - bool NeXTRuntimeIsDefault - = (IsRewriter || IsModernRewriter || - getToolChain().getTriple().isOSDarwin()); - if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, - NeXTRuntimeIsDefault)) { - objCRuntime.setKind(ObjCRuntime::NeXT); - } else { - CmdArgs.push_back("-fgnu-runtime"); - objCRuntime.setKind(ObjCRuntime::GNU); - } - getToolChain().configureObjCRuntime(objCRuntime); - if (objCRuntime.HasARC) - CmdArgs.push_back("-fobjc-runtime-has-arc"); - if (objCRuntime.HasWeak) - CmdArgs.push_back("-fobjc-runtime-has-weak"); - if (objCRuntime.HasTerminate) - CmdArgs.push_back("-fobjc-runtime-has-terminate"); - - // Compute the Objective-C ABI "version" to use. Version numbers are - // slightly confusing for historical reasons: - // 1 - Traditional "fragile" ABI - // 2 - Non-fragile ABI, version 1 - // 3 - Non-fragile ABI, version 2 - objcABIVersion = 1; - // If -fobjc-abi-version= is present, use that to set the version. - if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { - if (StringRef(A->getValue(Args)) == "1") - objcABIVersion = 1; - else if (StringRef(A->getValue(Args)) == "2") - objcABIVersion = 2; - else if (StringRef(A->getValue(Args)) == "3") - objcABIVersion = 3; - else - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); - } else { - // Otherwise, determine if we are using the non-fragile ABI. - bool NonFragileABIIsDefault = - (IsModernRewriter || - (!IsRewriter && getToolChain().IsObjCNonFragileABIDefault())); - if (Args.hasFlag(options::OPT_fobjc_nonfragile_abi, - options::OPT_fno_objc_nonfragile_abi, - NonFragileABIIsDefault)) { - // Determine the non-fragile ABI version to use. -#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO - unsigned NonFragileABIVersion = 1; -#else - unsigned NonFragileABIVersion = 2; -#endif - - if (Arg *A = Args.getLastArg( - options::OPT_fobjc_nonfragile_abi_version_EQ)) { - if (StringRef(A->getValue(Args)) == "1") - NonFragileABIVersion = 1; - else if (StringRef(A->getValue(Args)) == "2") - NonFragileABIVersion = 2; - else - D.Diag(diag::err_drv_clang_unsupported) - << A->getAsString(Args); - } - - objcABIVersion = 1 + NonFragileABIVersion; - } else { - objcABIVersion = 1; - } - } + ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); - if (objcABIVersion == 1) { - CmdArgs.push_back("-fobjc-fragile-abi"); - } else { - // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and - // legacy is the default. + // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and + // legacy is the default. + if (objcRuntime.isNonFragile()) { if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, options::OPT_fno_objc_legacy_dispatch, getToolChain().IsObjCLegacyDispatchDefault())) { @@ -2561,7 +2490,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fobjc-infer-related-result-type is the default, except in the Objective-C // rewriter. - if (IsRewriter || IsModernRewriter) + if (rewriteKind != RK_None) CmdArgs.push_back("-fno-objc-infer-related-result-type"); // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only @@ -2584,7 +2513,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add exception args. addExceptionArgs(Args, InputType, getToolChain().getTriple(), - KernelOrKext, objcABIVersion, CmdArgs); + KernelOrKext, objcRuntime, CmdArgs); if (getToolChain().UseSjLjExceptions()) CmdArgs.push_back("-fsjlj-exceptions"); @@ -2873,6 +2802,126 @@ void ClangAs::AddARMTargetArgs(const ArgList &Args, addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple)); } +/// Add options related to the Objective-C runtime/ABI. +/// +/// Returns true if the runtime is non-fragile. +ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, + ArgStringList &cmdArgs, + RewriteKind rewriteKind) const { + // Look for the controlling runtime option. + Arg *runtimeArg = args.getLastArg(options::OPT_fnext_runtime, + options::OPT_fgnu_runtime, + options::OPT_fobjc_runtime_EQ); + + // Just forward -fobjc-runtime= to the frontend. This supercedes + // options about fragility. + if (runtimeArg && + runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) { + ObjCRuntime runtime; + StringRef value = runtimeArg->getValue(args); + if (runtime.tryParse(value)) { + getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) + << value; + } + + runtimeArg->render(args, cmdArgs); + return runtime; + } + + // Otherwise, we'll need the ABI "version". Version numbers are + // slightly confusing for historical reasons: + // 1 - Traditional "fragile" ABI + // 2 - Non-fragile ABI, version 1 + // 3 - Non-fragile ABI, version 2 + unsigned objcABIVersion = 1; + // If -fobjc-abi-version= is present, use that to set the version. + if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { + StringRef value = abiArg->getValue(args); + if (value == "1") + objcABIVersion = 1; + else if (value == "2") + objcABIVersion = 2; + else if (value == "3") + objcABIVersion = 3; + else + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) + << value; + } else { + // Otherwise, determine if we are using the non-fragile ABI. + bool nonFragileABIIsDefault = + (rewriteKind == RK_NonFragile || + (rewriteKind == RK_None && + getToolChain().IsObjCNonFragileABIDefault())); + if (args.hasFlag(options::OPT_fobjc_nonfragile_abi, + options::OPT_fno_objc_nonfragile_abi, + nonFragileABIIsDefault)) { + // Determine the non-fragile ABI version to use. +#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO + unsigned nonFragileABIVersion = 1; +#else + unsigned nonFragileABIVersion = 2; +#endif + + if (Arg *abiArg = args.getLastArg( + options::OPT_fobjc_nonfragile_abi_version_EQ)) { + StringRef value = abiArg->getValue(args); + if (value == "1") + nonFragileABIVersion = 1; + else if (value == "2") + nonFragileABIVersion = 2; + else + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) + << value; + } + + objcABIVersion = 1 + nonFragileABIVersion; + } else { + objcABIVersion = 1; + } + } + + // We don't actually care about the ABI version other than whether + // it's non-fragile. + bool isNonFragile = objcABIVersion != 1; + + // If we have no runtime argument, ask the toolchain for its default runtime. + // However, the rewriter only really supports the Mac runtime, so assume that. + ObjCRuntime runtime; + if (!runtimeArg) { + switch (rewriteKind) { + case RK_None: + runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); + break; + case RK_Fragile: + runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple()); + break; + case RK_NonFragile: + runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); + break; + } + + // -fnext-runtime + } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) { + // On Darwin, make this use the default behavior for the toolchain. + if (getToolChain().getTriple().isOSDarwin()) { + runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); + + // Otherwise, build for a generic macosx port. + } else { + runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); + } + + // -fgnu-runtime + } else { + assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime)); + runtime = ObjCRuntime(ObjCRuntime::GNU, VersionTuple()); + } + + cmdArgs.push_back(args.MakeArgString( + "-fobjc-runtime=" + runtime.getAsString())); + return runtime; +} + void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -4340,11 +4389,11 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // If we don't have ARC or subscripting runtime support, link in the // runtime stubs. We have to do this *before* adding any of the normal // linker inputs so that its initializer gets run first. - ObjCRuntime runtime; - getDarwinToolChain().configureObjCRuntime(runtime); + ObjCRuntime runtime = + getDarwinToolChain().getDefaultObjCRuntime(/*nonfragile*/ true); // We use arclite library for both ARC and subscripting support. - if ((!runtime.HasARC && isObjCAutoRefCount(Args)) || - !runtime.HasSubscripting) + if ((!runtime.hasARC() && isObjCAutoRefCount(Args)) || + !runtime.hasSubscripting()) getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs); } CmdArgs.push_back("-framework"); diff --git a/clang/lib/Driver/Tools.h b/clang/lib/Driver/Tools.h index aa15f3551c1..0fc0690db52 100644 --- a/clang/lib/Driver/Tools.h +++ b/clang/lib/Driver/Tools.h @@ -18,6 +18,8 @@ #include "llvm/Support/Compiler.h" namespace clang { + class ObjCRuntime; + namespace driver { class Driver; @@ -44,6 +46,11 @@ namespace tools { void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const; + enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; + + ObjCRuntime AddObjCRuntimeArgs(const ArgList &args, ArgStringList &cmdArgs, + RewriteKind rewrite) const; + public: Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {} diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 6f55a02550d..8a95c80e49f 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -206,10 +206,6 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir); if (!Opts.DwarfDebugFlags.empty()) Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags); - if (Opts.ObjCRuntimeHasARC) - Res.push_back("-fobjc-runtime-has-arc"); - if (Opts.ObjCRuntimeHasTerminate) - Res.push_back("-fobjc-runtime-has-terminate"); if (Opts.EmitGcovArcs) Res.push_back("-femit-coverage-data"); if (Opts.EmitGcovNotes) @@ -678,8 +674,6 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); if (Opts.Borland) Res.push_back("-fborland-extensions"); - if (!Opts.ObjCNonFragileABI) - Res.push_back("-fobjc-fragile-abi"); if (Opts.ObjCDefaultSynthProperties) Res.push_back("-fobjc-default-synthesize-properties"); // NoInline is implicit. @@ -715,8 +709,6 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-fno-rtti"); if (Opts.MSBitfields) Res.push_back("-mms-bitfields"); - if (!Opts.NeXTRuntime) - Res.push_back("-fgnu-runtime"); if (Opts.Freestanding) Res.push_back("-ffreestanding"); if (Opts.NoBuiltin) @@ -786,6 +778,7 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { Res.push_back("-fobjc-gc-only"); } } + Res.push_back("-fobjc-runtime=" + Opts.ObjCRuntime.getAsString()); if (Opts.ObjCAutoRefCount) Res.push_back("-fobjc-arc"); if (Opts.ObjCRuntimeHasWeak) @@ -1190,8 +1183,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); - Opts.ObjCRuntimeHasARC = Args.hasArg(OPT_fobjc_runtime_has_arc); - Opts.ObjCRuntimeHasTerminate = Args.hasArg(OPT_fobjc_runtime_has_terminate); Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); @@ -1880,16 +1871,23 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.CXXOperatorNames = 0; if (Opts.ObjC1) { + if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { + StringRef value = arg->getValue(Args); + if (Opts.ObjCRuntime.tryParse(value)) + Diags.Report(diag::err_drv_unknown_objc_runtime) << value; + } + if (Args.hasArg(OPT_fobjc_gc_only)) Opts.setGC(LangOptions::GCOnly); else if (Args.hasArg(OPT_fobjc_gc)) Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; - if (Args.hasArg(OPT_fobjc_fragile_abi)) + if (!Opts.ObjCRuntime.isNonFragile()) Diags.Report(diag::err_arc_nonfragile_abi); } + Opts.ObjCRuntimeHasWeak = Opts.ObjCRuntime.hasWeak(); if (Args.hasArg(OPT_fobjc_runtime_has_weak)) Opts.ObjCRuntimeHasWeak = 1; @@ -1992,12 +1990,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ, 0, Diags); Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields); - Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); Opts.ObjCConstantStringClass = Args.getLastArgValue(OPT_fconstant_string_class); - Opts.ObjCNonFragileABI = !Args.hasArg(OPT_fobjc_fragile_abi); - if (Opts.ObjCNonFragileABI) - Opts.ObjCNonFragileABI2 = true; Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index bd08f5c09d2..6120d117e3c 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -365,7 +365,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); if (LangOpts.ObjC1) { - if (LangOpts.ObjCNonFragileABI) { + if (LangOpts.ObjCRuntime.isNonFragile()) { Builder.defineMacro("__OBJC2__"); if (LangOpts.ObjCExceptions) @@ -375,7 +375,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.getGC() != LangOptions::NonGC) Builder.defineMacro("__OBJC_GC__"); - if (LangOpts.NeXTRuntime) + if (LangOpts.ObjCRuntime.isNeXTFamily()) Builder.defineMacro("__NEXT_RUNTIME__"); Builder.defineMacro("IBOutlet", "__attribute__((iboutlet))"); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 3c14b7ce8cd..826fa03621c 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -643,13 +643,13 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("objc_fixed_enum", LangOpts.ObjC2) .Case("objc_instancetype", LangOpts.ObjC2) .Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules) - .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) - .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) + .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile()) + .Case("objc_weak_class", LangOpts.ObjCRuntime.isNonFragile()) .Case("ownership_holds", true) .Case("ownership_returns", true) .Case("ownership_takes", true) .Case("objc_bool", true) - .Case("objc_subscripting", LangOpts.ObjCNonFragileABI) + .Case("objc_subscripting", LangOpts.ObjCRuntime.isNonFragile()) .Case("objc_array_literals", LangOpts.ObjC2) .Case("objc_dictionary_literals", LangOpts.ObjC2) .Case("objc_boxed_expressions", LangOpts.ObjC2) diff --git a/clang/lib/Rewrite/FrontendActions.cpp b/clang/lib/Rewrite/FrontendActions.cpp index fa58575258e..9bc218e994f 100644 --- a/clang/lib/Rewrite/FrontendActions.cpp +++ b/clang/lib/Rewrite/FrontendActions.cpp @@ -155,7 +155,7 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { - if (CI.getLangOpts().ObjCNonFragileABI) + if (CI.getLangOpts().ObjCRuntime.isNonFragile()) return CreateModernObjCRewriter(InFile, OS, CI.getDiagnostics(), CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 81b22141e15..f04fc153af5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9571,7 +9571,7 @@ Decl *Sema::ActOnIvar(Scope *S, ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { - if (!LangOpts.ObjCNonFragileABI2) { + if (LangOpts.ObjCRuntime.isFragile()) { // Case of ivar declared in an implementation. Context is that of its class. EnclosingContext = IMPDecl->getClassInterface(); assert(EnclosingContext && "Implementation has no class interface!"); @@ -9581,7 +9581,7 @@ Decl *Sema::ActOnIvar(Scope *S, } else { if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { - if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) { + if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) { Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); return 0; } @@ -9625,7 +9625,7 @@ Decl *Sema::ActOnIvar(Scope *S, IdResolver.AddDecl(NewID); } - if (LangOpts.ObjCNonFragileABI2 && + if (LangOpts.ObjCRuntime.isNonFragile() && !NewID->isInvalidDecl() && isa<ObjCInterfaceDecl>(EnclosingDecl)) Diag(Loc, diag::warn_ivars_in_interface); @@ -9638,7 +9638,7 @@ Decl *Sema::ActOnIvar(Scope *S, /// then add an implicit `char :0` ivar to the end of that interface. void Sema::ActOnLastBitfield(SourceLocation DeclLoc, SmallVectorImpl<Decl *> &AllIvarDecls) { - if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty()) + if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty()) return; Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 490ee5739af..2a11c745935 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9626,7 +9626,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Diag(Loc, diag::err_objc_object_catch); Invalid = true; } else if (T->isObjCObjectPointerType()) { - if (!getLangOpts().ObjCNonFragileABI) + // FIXME: should this be a test for macosx-fragile specifically? + if (getLangOpts().ObjCRuntime.isFragile()) Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile); } } diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 80596bfe8c3..a673d247edc 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1039,7 +1039,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, return; assert(ivars && "missing @implementation ivars"); - if (LangOpts.ObjCNonFragileABI2) { + if (LangOpts.ObjCRuntime.isNonFragile()) { if (ImpDecl->getSuperClass()) Diag(ImpDecl->getLocation(), diag::warn_on_superclass_use); for (unsigned i = 0; i < numIvars; i++) { @@ -1501,7 +1501,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, ObjCInterfaceDecl *Super = IDecl->getSuperClass(); ObjCInterfaceDecl *NSIDecl = 0; - if (getLangOpts().NeXTRuntime) { + if (getLangOpts().ObjCRuntime.isNeXTFamily()) { // check to see if class implements forwardInvocation method and objects // of this class are derived from 'NSProxy' so that to forward requests // from one object to another. @@ -1730,8 +1730,9 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) - if (!(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) || - IDecl->isObjCRequiresPropertyDefs()) + if (!(LangOpts.ObjCDefaultSynthProperties && + LangOpts.ObjCRuntime.isNonFragile()) || + IDecl->isObjCRequiresPropertyDefs()) DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); SelectorSet ClsMap; @@ -2360,7 +2361,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(IDecl->getLocation(), diag::err_objc_root_class_subclass); } - if (LangOpts.ObjCNonFragileABI2) { + if (LangOpts.ObjCRuntime.isNonFragile()) { while (IDecl->getSuperClass()) { DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass()); IDecl = IDecl->getSuperClass(); @@ -2958,7 +2959,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, Diag(DeclStart, diag::err_undef_interface) << ClassName; return; } - if (LangOpts.ObjCNonFragileABI) { + if (LangOpts.ObjCRuntime.isNonFragile()) { Diag(DeclStart, diag::err_atdef_nonfragile_interface); return; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 49c84664fce..47fac59a342 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2913,7 +2913,7 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, SourceRange ArgRange, UnaryExprOrTypeTrait TraitKind) { // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. - if (S.LangOpts.ObjCNonFragileABI && T->isObjCObjectType()) { + if (S.LangOpts.ObjCRuntime.isNonFragile() && T->isObjCObjectType()) { S.Diag(Loc, diag::err_sizeof_nonfragile_interface) << T << (TraitKind == UETT_SizeOf) << ArgRange; @@ -3362,7 +3362,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, return ExprError(); // Diagnose bad cases where we step over interface counts. - if (ResultType->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { + if (ResultType->isObjCObjectType() && LangOpts.ObjCRuntime.isNonFragile()) { Diag(LLoc, diag::err_subscript_nonfragile_interface) << ResultType << BaseExpr->getSourceRange(); return ExprError(); @@ -6256,7 +6256,7 @@ static bool checkArithmethicPointerOnNonFragileABI(Sema &S, Expr *Op) { assert(Op->getType()->isAnyPointerType()); QualType PointeeTy = Op->getType()->getPointeeType(); - if (!PointeeTy->isObjCObjectType() || !S.LangOpts.ObjCNonFragileABI) + if (!PointeeTy->isObjCObjectType() || S.LangOpts.ObjCRuntime.isFragile()) return true; S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index c1df87370c3..9466f4146ef 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -579,9 +579,10 @@ ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod) { - // Feature support is for modern abi. - if (!LangOpts.ObjCNonFragileABI) + // Subscripting is only supported in the non-fragile ABI. + if (LangOpts.ObjCRuntime.isFragile()) return ExprError(); + // If the expression is type-dependent, there's nothing for us to do. assert ((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) && "base or index cannot have dependent type here"); diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 20dbf58c986..71112f7701e 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -827,12 +827,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, IDecl->makeDeclVisibleInContext(Ivar); property->setPropertyIvarDecl(Ivar); - if (!getLangOpts().ObjCNonFragileABI) + if (getLangOpts().ObjCRuntime.isFragile()) Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl) << PropertyId; // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. - } else if (getLangOpts().ObjCNonFragileABI && + } else if (getLangOpts().ObjCRuntime.isNonFragile() && !declaresSameEntity(ClassDeclared, IDecl)) { Diag(PropertyDiagLoc, diag::error_ivar_in_superclass_use) << property->getDeclName() << Ivar->getDeclName() @@ -1006,7 +1006,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } IC->addPropertyImplementation(PIDecl); if (getLangOpts().ObjCDefaultSynthProperties && - getLangOpts().ObjCNonFragileABI2 && + getLangOpts().ObjCRuntime.isNonFragile() && !IDecl->isObjCRequiresPropertyDefs()) { // Diagnose if an ivar was lazily synthesdized due to a previous // use and if 1) property is @dynamic or 2) property is synthesized @@ -1527,7 +1527,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, } void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { - if (!LangOpts.ObjCDefaultSynthProperties || !LangOpts.ObjCNonFragileABI2) + if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile()) return; ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D); if (!IC) @@ -1571,7 +1571,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, << Prop->getDeclName() << Prop->getGetterName(); Diag(Prop->getLocation(), diag::note_property_declare); - if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) + if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile()) if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl)) if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs()) Diag(RID->getLocation(), diag::note_suppressed_class_declare); @@ -1586,7 +1586,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, << Prop->getDeclName() << Prop->getSetterName(); Diag(Prop->getLocation(), diag::note_property_declare); - if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCNonFragileABI2) + if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile()) if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl)) if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs()) Diag(RID->getLocation(), diag::note_suppressed_class_declare); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index da031575a2f..9f10a0b7413 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -90,6 +90,12 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" + + if (PPLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { + Reader.Diag(diag::err_pch_langopt_value_mismatch) + << "target Objective-C runtime"; + return true; + } return false; } @@ -3323,8 +3329,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { /// them to the AST listener if one is set. /// /// \returns true if the listener deems the file unacceptable, false otherwise. -bool ASTReader::ParseLanguageOptions( - const SmallVectorImpl<uint64_t> &Record) { +bool ASTReader::ParseLanguageOptions(const RecordData &Record) { if (Listener) { LangOptions LangOpts; unsigned Idx = 0; @@ -3333,6 +3338,10 @@ bool ASTReader::ParseLanguageOptions( #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++])); #include "clang/Basic/LangOptions.def" + + ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; + VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); + LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); unsigned Length = Record[Idx++]; LangOpts.CurrentModule.assign(Record.begin() + Idx, diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 1f961805073..17fef95b6f2 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1081,6 +1081,9 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ Record.push_back(static_cast<unsigned>(LangOpts.get##Name())); #include "clang/Basic/LangOptions.def" + + Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind()); + AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record); Record.push_back(LangOpts.CurrentModule.size()); Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end()); |

