diff options
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()); |