diff options
| author | John McCall <rjmccall@apple.com> | 2011-06-15 23:02:42 +0000 |
|---|---|---|
| committer | John McCall <rjmccall@apple.com> | 2011-06-15 23:02:42 +0000 |
| commit | 31168b077c3687bb79985102b08718cd77db353d (patch) | |
| tree | 489434d90661950c25716a5db40be446d933c95c /clang/lib/AST | |
| parent | ce45f88e451387c46bfd6b53c75c7fa72b730ba1 (diff) | |
| download | bcm5719-llvm-31168b077c3687bb79985102b08718cd77db353d.tar.gz bcm5719-llvm-31168b077c3687bb79985102b08718cd77db353d.zip | |
Automatic Reference Counting.
Language-design credit goes to a lot of people, but I particularly want
to single out Blaine Garst and Patrick Beard for their contributions.
Compiler implementation credit goes to Argyrios, Doug, Fariborz, and myself,
in no particular order.
llvm-svn: 133103
Diffstat (limited to 'clang/lib/AST')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 52 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 36 | ||||
| -rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 24 | ||||
| -rw-r--r-- | clang/lib/AST/DeclPrinter.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 36 | ||||
| -rw-r--r-- | clang/lib/AST/ExprClassification.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 19 | ||||
| -rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 42 | ||||
| -rw-r--r-- | clang/lib/AST/ParentMap.cpp | 9 | ||||
| -rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 407 | ||||
| -rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 117 |
13 files changed, 634 insertions, 147 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4c66ed8d7e0..fac2eacc4f0 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -221,9 +221,9 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, DependentTemplateSpecializationTypes(this_()), GlobalNestedNameSpecifier(0), IsInt128Installed(false), CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0), - ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), - sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), - cudaConfigureCallDecl(0), + ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), + jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), + BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), NullTypeSourceInfo(QualType()), SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t), @@ -2040,10 +2040,13 @@ ASTContext::getFunctionType(QualType ResultTy, assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } - // FunctionProtoType objects are allocated with extra bytes after them - // for two variable size arrays (for parameter and exception types) at the - // end of them. Instead of the exception types, there could be a noexcept - // expression and a context pointer. + // FunctionProtoType objects are allocated with extra bytes after + // them for three variable size arrays at the end: + // - parameter types + // - exception types + // - consumed-arguments flags + // Instead of the exception types, there could be a noexcept + // expression. size_t Size = sizeof(FunctionProtoType) + NumArgs * sizeof(QualType); if (EPI.ExceptionSpecType == EST_Dynamic) @@ -2051,6 +2054,9 @@ ASTContext::getFunctionType(QualType ResultTy, else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { Size += sizeof(Expr*); } + if (EPI.ConsumedArguments) + Size += NumArgs * sizeof(bool); + FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); @@ -2925,7 +2931,6 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const { return CanQualType::CreateUnsafe(Result); } - QualType ASTContext::getUnqualifiedArrayType(QualType type, Qualifiers &quals) { SplitQualType splitType = type.getSplitUnqualifiedType(); @@ -3725,11 +3730,7 @@ void ASTContext::setBlockDescriptorExtendedType(QualType T) { } bool ASTContext::BlockRequiresCopying(QualType Ty) const { - if (Ty->isBlockPointerType()) - return true; - if (isObjCNSObjectType(Ty)) - return true; - if (Ty->isObjCObjectPointerType()) + if (Ty->isObjCRetainableType()) return true; if (getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { @@ -4826,20 +4827,6 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const { // Type Predicates. //===----------------------------------------------------------------------===// -/// isObjCNSObjectType - Return true if this is an NSObject object using -/// NSObject attribute on a c-style pointer type. -/// FIXME - Make it work directly on types. -/// FIXME: Move to Type. -/// -bool ASTContext::isObjCNSObjectType(QualType Ty) const { - if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { - if (TypedefNameDecl *TD = TDT->getDecl()) - if (TD->getAttr<ObjCNSObjectAttr>()) - return true; - } - return false; -} - /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// @@ -5452,6 +5439,9 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) return QualType(); + if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) + return QualType(); + // It's noreturn if either type is. // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); @@ -5460,10 +5450,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (NoReturn != rbaseInfo.getNoReturn()) allRTypes = false; - FunctionType::ExtInfo einfo(NoReturn, - lbaseInfo.getHasRegParm(), - lbaseInfo.getRegParm(), - lbaseInfo.getCC()); + FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn); if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -5584,7 +5571,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // If any of these qualifiers are different, we have a type // mismatch. if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || - LQuals.getAddressSpace() != RQuals.getAddressSpace()) + LQuals.getAddressSpace() != RQuals.getAddressSpace() || + LQuals.getObjCLifetime() != RQuals.getObjCLifetime()) return QualType(); // Exactly one GC qualifier difference is allowed: __strong is diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 08ac2a5be4d..c10e6c40d39 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -228,6 +228,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasTrivialDestructor()) data().HasTrivialDestructor = false; + // A class has an Objective-C object member if... or any of its bases + // has an Objective-C object member. + if (BaseClassDecl->hasObjectMember()) + setHasObjectMember(true); + // Keep track of the presence of mutable fields. if (BaseClassDecl->hasMutableFields()) data().HasMutableFields = true; @@ -698,10 +703,23 @@ NotASpecialMember:; // A POD struct is a class that is both a trivial class and a // standard-layout class, and has no non-static data members of type // non-POD struct, non-POD union (or array of such types). + // + // Automatic Reference Counting: the presence of a member of Objective-C pointer type + // that does not explicitly have no lifetime makes the class a non-POD. + // However, we delay setting PlainOldData to false in this case so that + // Sema has a chance to diagnostic causes where the same class will be + // non-POD with Automatic Reference Counting but a POD without Instant Objects. + // In this case, the class will become a non-POD class when we complete + // the definition. ASTContext &Context = getASTContext(); QualType T = Context.getBaseElementType(Field->getType()); - if (!T->isPODType()) + if (T->isObjCRetainableType() || T.isObjCGCStrong()) { + if (!Context.getLangOptions().ObjCAutoRefCount || + T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) + setHasObjectMember(true); + } else if (!T.isPODType(Context)) data().PlainOldData = false; + if (T->isReferenceType()) { data().HasTrivialDefaultConstructor = false; @@ -768,6 +786,8 @@ NotASpecialMember:; if (!FieldRec->hasTrivialDestructor()) data().HasTrivialDestructor = false; + if (FieldRec->hasObjectMember()) + setHasObjectMember(true); // C++0x [class]p7: // A standard-layout class is a class that: @@ -1078,6 +1098,20 @@ void CXXRecordDecl::completeDefinition() { void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { RecordDecl::completeDefinition(); + if (hasObjectMember() && getASTContext().getLangOptions().ObjCAutoRefCount) { + // Objective-C Automatic Reference Counting: + // If a class has a non-static data member of Objective-C pointer + // type (or array thereof), it is a non-POD type and its + // default constructor (if any), copy constructor, copy assignment + // operator, and destructor are non-trivial. + struct DefinitionData &Data = data(); + Data.PlainOldData = false; + Data.HasTrivialDefaultConstructor = false; + Data.HasTrivialCopyConstructor = false; + Data.HasTrivialCopyAssignment = false; + Data.HasTrivialDestructor = false; + } + // If the class may be abstract (but hasn't been marked as such), check for // any pure final overriders. if (mayBeAbstract()) { diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index e2c4f38ff9b..99eb0d386bd 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -474,8 +474,28 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, } else // we have a factory method. selfTy = Context.getObjCClassType(); - setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), - &Context.Idents.get("self"), selfTy)); + bool selfIsConsumed = false; + if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) { + selfIsConsumed = hasAttr<NSConsumesSelfAttr>(); + + // 'self' is always __strong, although as a special case we don't + // actually retain it except in init methods. + Qualifiers qs; + qs.setObjCLifetime(Qualifiers::OCL_Strong); + selfTy = Context.getQualifiedType(selfTy, qs); + + // In addition, 'self' is const unless this is an init method. + if (getMethodFamily() != OMF_init) + selfTy = selfTy.withConst(); + } + + ImplicitParamDecl *self + = ImplicitParamDecl::Create(Context, this, SourceLocation(), + &Context.Idents.get("self"), selfTy); + setSelfDecl(self); + + if (selfIsConsumed) + self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context)); setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("_cmd"), diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 421770ea70f..19554a3baae 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -933,6 +933,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { first = false; } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) { + Out << (first ? ' ' : ',') << "strong"; + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { Out << (first ? ' ' : ',') << "copy"; first = false; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 987213907e4..97f4ea6cba2 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1045,6 +1045,10 @@ const char *CastExpr::getCastKindName() const { return "IntegralComplexCast"; case CK_IntegralComplexToFloatingComplex: return "IntegralComplexToFloatingComplex"; + case CK_ObjCConsumeObject: + return "ObjCConsumeObject"; + case CK_ObjCProduceObject: + return "ObjCProduceObject"; } llvm_unreachable("Unhandled cast kind!"); @@ -1490,6 +1494,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case ObjCMessageExprClass: { const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this); + if (Ctx.getLangOptions().ObjCAutoRefCount && + ME->isInstanceMessage() && + !ME->getType()->isVoidType() && + ME->getSelector().getIdentifierInfoForSlot(0) && + ME->getSelector().getIdentifierInfoForSlot(0) + ->getName().startswith("init")) { + Loc = getExprLoc(); + R1 = ME->getSourceRange(); + return true; + } + const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr<WarnUnusedResultAttr>()) { Loc = getExprLoc(); @@ -2519,7 +2534,7 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, /*TypeDependent=*/false, /*ValueDependent=*/false, /*ContainsUnexpandedParameterPack=*/false), NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), - HasMethod(Method != 0), SuperLoc(SuperLoc), + HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) @@ -2540,7 +2555,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, SourceLocation RBracLoc) : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->containsUnexpandedParameterPack()), - NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), + NumArgs(NumArgs), Kind(Class), + HasMethod(Method != 0), IsDelegateInitCall(false), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) @@ -2571,7 +2587,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(), Receiver->isTypeDependent(), Receiver->containsUnexpandedParameterPack()), - NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), + NumArgs(NumArgs), Kind(Instance), + HasMethod(Method != 0), IsDelegateInitCall(false), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) @@ -2702,6 +2719,19 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { return 0; } +llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const { + switch (getBridgeKind()) { + case OBC_Bridge: + return "__bridge"; + case OBC_BridgeTransfer: + return "__bridge_transfer"; + case OBC_BridgeRetained: + return "__bridge_retained"; + } + + return "__bridge"; +} + bool ChooseExpr::isConditionTrue(const ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; } diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index d177cb5cbc9..1a1fa91a40a 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -162,6 +162,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::SizeOfPackExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: return Cl::CL_PRValue; // Next come the complicated cases. @@ -289,6 +290,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: + case Expr::ObjCBridgedCastExprClass: // Only in C++ can casts be interesting at all. if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten()); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 06c5645afb3..432ffee08de 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -282,6 +282,17 @@ public: return true; return false; } + bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + // We don't want to evaluate BlockExprs multiple times, as they generate // a ton of code. bool VisitBlockExpr(const BlockExpr *E) { return true; } @@ -1797,6 +1808,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_GetObjCProperty: case CK_LValueBitCast: case CK_UserDefinedConversion: + case CK_ObjCProduceObject: + case CK_ObjCConsumeObject: return false; case CK_LValueToRValue: @@ -2301,6 +2314,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_FloatingComplexToBoolean: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: + case CK_ObjCProduceObject: + case CK_ObjCConsumeObject: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: @@ -2771,6 +2786,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: + case Expr::ObjCIndirectCopyRestoreExprClass: return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: @@ -2995,7 +3011,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXFunctionalCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXReinterpretCastExprClass: - case Expr::CXXConstCastExprClass: { + case Expr::CXXConstCastExprClass: + case Expr::ObjCBridgedCastExprClass: { const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); if (SubExpr->getType()->isIntegralOrEnumerationType()) return CheckICE(SubExpr, Ctx); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index e81ec7e54b6..a77fe5f48ab 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/ABI.h" #include "clang/Basic/SourceManager.h" @@ -1464,7 +1465,35 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { Out << 'U' << ASString.size() << ASString; } - // FIXME: For now, just drop all extension qualifiers on the floor. + llvm::StringRef LifetimeName; + switch (Quals.getObjCLifetime()) { + // Objective-C ARC Extension: + // + // <type> ::= U "__strong" + // <type> ::= U "__weak" + // <type> ::= U "__autoreleasing" + // <type> ::= U "__unsafe_unretained" + case Qualifiers::OCL_None: + break; + + case Qualifiers::OCL_Weak: + LifetimeName = "__weak"; + break; + + case Qualifiers::OCL_Strong: + LifetimeName = "__strong"; + break; + + case Qualifiers::OCL_Autoreleasing: + LifetimeName = "__autoreleasing"; + break; + + case Qualifiers::OCL_ExplicitNone: + LifetimeName = "__unsafe_unretained"; + break; + } + if (!LifetimeName.empty()) + Out << 'U' << LifetimeName.size() << LifetimeName; } void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { @@ -2089,6 +2118,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::ObjCProtocolExprClass: case Expr::ObjCSelectorExprClass: case Expr::ObjCStringLiteralClass: + case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::OffsetOfExprClass: case Expr::PredefinedExprClass: case Expr::ShuffleVectorExprClass: @@ -2347,7 +2377,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity); break; } - + + case Expr::ObjCBridgedCastExprClass: { + // Mangle ownership casts as a vendor extended operator __bridge, + // __bridge_transfer, or __bridge_retain. + llvm::StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName(); + Out << "v1U" << Kind.size() << Kind; + } + // Fall through to mangle the cast itself. + case Expr::CStyleCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXDynamicCastExprClass: diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp index eca351aec8d..b7b2005e9f8 100644 --- a/clang/lib/AST/ParentMap.cpp +++ b/clang/lib/AST/ParentMap.cpp @@ -66,6 +66,15 @@ Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const { return S; } +Stmt *ParentMap::getOuterParenParent(Stmt *S) const { + Stmt *Paren = 0; + while (isa<ParenExpr>(S)) { + Paren = S; + S = getParent(S); + }; + return Paren; +} + bool ParentMap::isConsumedExpr(Expr* E) const { Stmt *P = getParent(E); Stmt *DirectChild = E; diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 87588e45188..d6a67b13ef7 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -449,6 +449,12 @@ void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) { OS << "\n"; } +void StmtPrinter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *Node) { + Indent() << "@autoreleasepool"; + PrintRawCompoundStmt(dyn_cast<CompoundStmt>(Node->getSubStmt())); + OS << "\n"; +} + void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) { OS << "catch ("; if (Decl *ExDecl = Node->getExceptionDecl()) @@ -1464,6 +1470,17 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "]"; } +void +StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { + PrintExpr(E->getSubExpr()); +} + +void +StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { + OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy) + << ")"; + PrintExpr(E->getSubExpr()); +} void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { BlockDecl *BD = Node->getBlockDecl(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index b117cd9a525..c70c87a7240 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -220,6 +220,10 @@ void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { + VisitStmt(S); +} + void StmtProfiler::VisitExpr(Expr *S) { VisitStmt(S); } @@ -952,6 +956,17 @@ void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) { ID.AddBoolean(S->isArrow()); } +void +StmtProfiler::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->shouldCopy()); +} + +void StmtProfiler::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *S) { + VisitExplicitCastExpr(S); + ID.AddBoolean(S->getBridgeKind()); +} + void StmtProfiler::VisitDecl(Decl *D) { ID.AddInteger(D? D->getKind() : 0); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 938a686c2b5..080bca2198a 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -36,7 +36,10 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { (hasObjCGCAttr() && !Other.hasObjCGCAttr())) && // Address space superset. ((getAddressSpace() == Other.getAddressSpace()) || - (hasAddressSpace()&& !Other.hasAddressSpace())); + (hasAddressSpace()&& !Other.hasAddressSpace())) && + // Lifetime qualifier superset. + ((getObjCLifetime() == Other.getObjCLifetime()) || + (hasObjCLifetime() && !Other.hasObjCLifetime())); } bool QualType::isConstant(QualType T, ASTContext &Ctx) { @@ -866,39 +869,59 @@ bool Type::isIncompleteType() const { } } -/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10) -bool Type::isPODType() const { +bool QualType::isPODType(ASTContext &Context) const { // The compiler shouldn't query this for incomplete types, but the user might. // We return false for that case. Except for incomplete arrays of PODs, which // are PODs according to the standard. - if (isIncompleteArrayType() && - cast<ArrayType>(CanonicalType)->getElementType()->isPODType()) - return true; - if (isIncompleteType()) + if (isNull()) + return 0; + + if ((*this)->isIncompleteArrayType()) + return Context.getBaseElementType(*this).isPODType(Context); + + if ((*this)->isIncompleteType()) return false; + if (Context.getLangOptions().ObjCAutoRefCount) { + switch (getObjCLifetime()) { + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_None: + if ((*this)->isObjCLifetimeType()) + return false; + break; + } + } + + QualType CanonicalType = getTypePtr()->CanonicalType; switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: return false; - case VariableArray: - case ConstantArray: + case Type::VariableArray: + case Type::ConstantArray: // IncompleteArray is handled above. - return cast<ArrayType>(CanonicalType)->getElementType()->isPODType(); - - case Builtin: - case Complex: - case Pointer: - case MemberPointer: - case Vector: - case ExtVector: - case ObjCObjectPointer: - case BlockPointer: + return Context.getBaseElementType(*this).isPODType(Context); + + case Type::ObjCObjectPointer: + case Type::BlockPointer: + case Type::Builtin: + case Type::Complex: + case Type::Pointer: + case Type::MemberPointer: + case Type::Vector: + case Type::ExtVector: return true; - case Enum: + case Type::Enum: return true; - case Record: + case Type::Record: if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) return ClassDecl->isPOD(); @@ -908,6 +931,121 @@ bool Type::isPODType() const { } } +bool QualType::isTrivialType(ASTContext &Context) const { + // The compiler shouldn't query this for incomplete types, but the user might. + // We return false for that case. Except for incomplete arrays of PODs, which + // are PODs according to the standard. + if (isNull()) + return 0; + + if ((*this)->isArrayType()) + return Context.getBaseElementType(*this).isTrivialType(Context); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if ((*this)->isIncompleteType()) + return false; + + if (Context.getLangOptions().ObjCAutoRefCount) { + switch (getObjCLifetime()) { + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_None: + if ((*this)->isObjCLifetimeType()) + return false; + break; + } + } + + QualType CanonicalType = getTypePtr()->CanonicalType; + if (CanonicalType->isDependentType()) + return false; + + // C++0x [basic.types]p9: + // Scalar types, trivial class types, arrays of such types, and + // cv-qualified versions of these types are collectively called trivial + // types. + + // As an extension, Clang treats vector types as Scalar types. + if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) + return true; + if (const RecordType *RT = CanonicalType->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // C++0x [class]p5: + // A trivial class is a class that has a trivial default constructor + if (!ClassDecl->hasTrivialDefaultConstructor()) return false; + // and is trivially copyable. + if (!ClassDecl->isTriviallyCopyable()) return false; + } + + return true; + } + + // No other types can match. + return false; +} + +bool QualType::isTriviallyCopyableType(ASTContext &Context) const { + if ((*this)->isArrayType()) + return Context.getBaseElementType(*this).isTrivialType(Context); + + if (Context.getLangOptions().ObjCAutoRefCount) { + switch (getObjCLifetime()) { + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_None: + if ((*this)->isObjCLifetimeType()) + return false; + break; + } + } + + // C++0x [basic.types]p9 + // Scalar types, trivially copyable class types, arrays of such types, and + // cv-qualified versions of these types are collectively called trivial + // types. + + QualType CanonicalType = getCanonicalType(); + if (CanonicalType->isDependentType()) + return false; + + // Return false for incomplete types after skipping any incomplete array types + // which are expressly allowed by the standard and thus our API. + if (CanonicalType->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) + return true; + + if (const RecordType *RT = CanonicalType->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (!ClassDecl->isTriviallyCopyable()) return false; + } + + return true; + } + + // No other types can match. + return false; +} + + + bool Type::isLiteralType() const { if (isDependentType()) return false; @@ -928,6 +1066,10 @@ bool Type::isLiteralType() const { if (BaseTy->isIncompleteType()) return false; + // Objective-C lifetime types are not literal types. + if (BaseTy->isObjCRetainableType()) + return false; + // C++0x [basic.types]p10: // A type is a literal type if it is: // -- a scalar type; or @@ -961,68 +1103,6 @@ bool Type::isLiteralType() const { return false; } -bool Type::isTrivialType() const { - if (isDependentType()) - return false; - - // C++0x [basic.types]p9: - // Scalar types, trivial class types, arrays of such types, and - // cv-qualified versions of these types are collectively called trivial - // types. - const Type *BaseTy = getBaseElementTypeUnsafe(); - assert(BaseTy && "NULL element type"); - - // Return false for incomplete types after skipping any incomplete array - // types which are expressly allowed by the standard and thus our API. - if (BaseTy->isIncompleteType()) - return false; - - // As an extension, Clang treats vector types as Scalar types. - if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; - if (const RecordType *RT = BaseTy->getAs<RecordType>()) { - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) { - if (!ClassDecl->isTrivial()) return false; - } - - return true; - } - - // No other types can match. - return false; -} - -bool Type::isTriviallyCopyableType() const { - if (isDependentType()) - return false; - - // C++0x [basic.types]p9 - // Scalar types, trivially copyable class types, arrays of such types, and - // cv-qualified versions of these types are collectively called trivial - // types. - const Type *BaseTy = getBaseElementTypeUnsafe(); - assert(BaseTy && "NULL element type"); - - // Return false for incomplete types after skipping any incomplete array types - // which are expressly allowed by the standard and thus our API. - if (BaseTy->isIncompleteType()) - return false; - - // As an extension, Clang treats vector types as Scalar types. - if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; - if (const RecordType *RT = BaseTy->getAs<RecordType>()) { - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) { - if (!ClassDecl->isTriviallyCopyable()) return false; - } - - return true; - } - - // No other types can match. - return false; -} - bool Type::isStandardLayoutType() const { if (isDependentType()) return false; @@ -1060,14 +1140,32 @@ bool Type::isStandardLayoutType() const { // This is effectively the intersection of isTrivialType and // isStandardLayoutType. We implement it dircetly to avoid redundant // conversions from a type to a CXXRecordDecl. -bool Type::isCXX11PODType() const { - if (isDependentType()) +bool QualType::isCXX11PODType(ASTContext &Context) const { + const Type *ty = getTypePtr(); + if (ty->isDependentType()) return false; + if (Context.getLangOptions().ObjCAutoRefCount) { + switch (getObjCLifetime()) { + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_None: + if (ty->isObjCLifetimeType()) + return false; + break; + } + } + // C++11 [basic.types]p9: // Scalar types, POD classes, arrays of such types, and cv-qualified // versions of these types are collectively called trivial types. - const Type *BaseTy = getBaseElementTypeUnsafe(); + const Type *BaseTy = ty->getBaseElementTypeUnsafe(); assert(BaseTy && "NULL element type"); // Return false for incomplete types after skipping any incomplete array @@ -1392,7 +1490,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, result->containsUnexpandedParameterPack(), epi.ExtInfo), NumArgs(numArgs), NumExceptions(epi.NumExceptions), - ExceptionSpecType(epi.ExceptionSpecType) + ExceptionSpecType(epi.ExceptionSpecType), + HasAnyConsumedArgs(epi.ConsumedArguments != 0) { // Fill in the trailing argument array. QualType *argSlot = reinterpret_cast<QualType*>(this+1); @@ -1423,6 +1522,12 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs); *noexSlot = epi.NoexceptExpr; } + + if (epi.ConsumedArguments) { + bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer()); + for (unsigned i = 0; i != numArgs; ++i) + consumedArgs[i] = epi.ConsumedArguments[i]; + } } FunctionProtoType::NoexceptResult @@ -1461,6 +1566,24 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumArgs, const ExtProtoInfo &epi, const ASTContext &Context) { + + // We have to be careful not to get ambiguous profile encodings. + // Note that valid type pointers are never ambiguous with anything else. + // + // The encoding grammar begins: + // type type* bool int bool + // If that final bool is true, then there is a section for the EH spec: + // bool type* + // This is followed by an optional "consumed argument" section of the + // same length as the first type sequence: + // bool* + // Finally, we have the ext info: + // int + // + // There is no ambiguity between the consumed arguments and an empty EH + // spec because of the leading 'bool' which unambiguously indicates + // whether the following bool is the EH spec or part of the arguments. + ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); @@ -1474,6 +1597,10 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ epi.NoexceptExpr->Profile(ID, Context, false); } + if (epi.ConsumedArguments) { + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddBoolean(epi.ConsumedArguments[i]); + } epi.ExtInfo.Profile(ID); } @@ -1900,6 +2027,79 @@ void Type::ClearLinkageCache() { CanonicalType->TypeBits.CacheValidAndVisibility = 0; } +Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { + if (isObjCARCImplicitlyUnretainedType()) + return Qualifiers::OCL_ExplicitNone; + return Qualifiers::OCL_Strong; +} + +bool Type::isObjCARCImplicitlyUnretainedType() const { + assert(isObjCLifetimeType() && + "cannot query implicit lifetime for non-inferrable type"); + + const Type *canon = getCanonicalTypeInternal().getTypePtr(); + + // Walk down to the base type. We don't care about qualifiers for this. + while (const ArrayType *array = dyn_cast<ArrayType>(canon)) + canon = array->getElementType().getTypePtr(); + + if (const ObjCObjectPointerType *opt + = dyn_cast<ObjCObjectPointerType>(canon)) { + // Class and Class<Protocol> don't require retension. + if (opt->getObjectType()->isObjCClass()) + return true; + } + + return false; +} + +bool Type::isObjCNSObjectType() const { + if (const TypedefType *typedefType = dyn_cast<TypedefType>(this)) + return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>(); + return false; +} +bool Type::isObjCRetainableType() const { + return isObjCObjectPointerType() || + isBlockPointerType() || + isObjCNSObjectType(); +} +bool Type::isObjCIndirectLifetimeType() const { + if (isObjCLifetimeType()) + return true; + if (const PointerType *OPT = getAs<PointerType>()) + return OPT->getPointeeType()->isObjCIndirectLifetimeType(); + if (const ReferenceType *Ref = getAs<ReferenceType>()) + return Ref->getPointeeType()->isObjCIndirectLifetimeType(); + if (const MemberPointerType *MemPtr = getAs<MemberPointerType>()) + return MemPtr->getPointeeType()->isObjCIndirectLifetimeType(); + return false; +} + +/// Returns true if objects of this type have lifetime semantics under +/// ARC. +bool Type::isObjCLifetimeType() const { + const Type *type = this; + while (const ArrayType *array = type->getAsArrayTypeUnsafe()) + type = array->getElementType().getTypePtr(); + return type->isObjCRetainableType(); +} + +/// \brief Determine whether the given type T is a "bridgable" Objective-C type, +/// which is either an Objective-C object pointer type or an +bool Type::isObjCARCBridgableType() const { + return isObjCObjectPointerType() || isBlockPointerType(); +} + +/// \brief Determine whether the given type T is a "bridgeable" C type. +bool Type::isCARCBridgableType() const { + const PointerType *Pointer = getAs<PointerType>(); + if (!Pointer) + return false; + + QualType Pointee = Pointer->getPointeeType(); + return Pointee->isVoidType() || Pointee->isRecordType(); +} + bool Type::hasSizedVLAType() const { if (!isVariablyModifiedType()) return false; @@ -1919,6 +2119,18 @@ bool Type::hasSizedVLAType() const { } QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { + switch (type.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + break; + + case Qualifiers::OCL_Strong: + return DK_objc_strong_lifetime; + case Qualifiers::OCL_Weak: + return DK_objc_weak_lifetime; + } + /// Currently, the only destruction kind we recognize is C++ objects /// with non-trivial destructors. const CXXRecordDecl *record = @@ -1928,3 +2140,24 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { return DK_none; } + +bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const { + switch (getObjCLifetime()) { + case Qualifiers::OCL_None: + break; + + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Autoreleasing: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + return !Context.getLangOptions().ObjCAutoRefCount; + } + + if (const CXXRecordDecl *Record + = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) + return Record->hasTrivialCopyAssignment(); + + return true; +} diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 4519606f6e8..ccb456018dd 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -24,6 +24,23 @@ using namespace clang; namespace { + /// \brief RAII object that enables printing of the ARC __strong lifetime + /// qualifier. + class IncludeStrongLifetimeRAII { + PrintingPolicy &Policy; + bool Old; + + public: + explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy) + : Policy(Policy), Old(Policy.SuppressStrongLifetime) { + Policy.SuppressStrongLifetime = false; + } + + ~IncludeStrongLifetimeRAII() { + Policy.SuppressStrongLifetime = Old; + } + }; + class TypePrinter { PrintingPolicy Policy; @@ -78,7 +95,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { // "int * const", printing "const int *" is different. Only do this when the // type expands to a simple string. bool CanPrefixQualifiers = false; - + bool NeedARCStrongQualifier = false; Type::TypeClass TC = T->getTypeClass(); if (const AutoType *AT = dyn_cast<AutoType>(T)) TC = AT->desugar()->getTypeClass(); @@ -114,15 +131,18 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType(); break; + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + NeedARCStrongQualifier = true; + // Fall through + case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: - case Type::ConstantArray: - case Type::IncompleteArray: - case Type::VariableArray: - case Type::DependentSizedArray: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -139,13 +159,20 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { if (!CanPrefixQualifiers && !Quals.empty()) { std::string qualsBuffer; - Quals.getAsStringInternal(qualsBuffer, Policy); + if (NeedARCStrongQualifier) { + IncludeStrongLifetimeRAII Strong(Policy); + Quals.getAsStringInternal(qualsBuffer, Policy); + } else { + Quals.getAsStringInternal(qualsBuffer, Policy); + } - if (!buffer.empty()) { - qualsBuffer += ' '; - qualsBuffer += buffer; + if (!qualsBuffer.empty()) { + if (!buffer.empty()) { + qualsBuffer += ' '; + qualsBuffer += buffer; + } + std::swap(buffer, qualsBuffer); } - std::swap(buffer, qualsBuffer); } switch (T->getTypeClass()) { @@ -159,13 +186,20 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { // If we're adding the qualifiers as a prefix, do it now. if (CanPrefixQualifiers && !Quals.empty()) { std::string qualsBuffer; - Quals.getAsStringInternal(qualsBuffer, Policy); - - if (!buffer.empty()) { - qualsBuffer += ' '; - qualsBuffer += buffer; + if (NeedARCStrongQualifier) { + IncludeStrongLifetimeRAII Strong(Policy); + Quals.getAsStringInternal(qualsBuffer, Policy); + } else { + Quals.getAsStringInternal(qualsBuffer, Policy); + } + + if (!qualsBuffer.empty()) { + if (!buffer.empty()) { + qualsBuffer += ' '; + qualsBuffer += buffer; + } + std::swap(buffer, qualsBuffer); } - std::swap(buffer, qualsBuffer); } } @@ -192,6 +226,7 @@ void TypePrinter::printPointer(const PointerType *T, std::string &S) { if (isa<ArrayType>(T->getPointeeType())) S = '(' + S + ')'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getPointeeType(), S); } @@ -209,6 +244,7 @@ void TypePrinter::printLValueReference(const LValueReferenceType *T, if (isa<ArrayType>(T->getPointeeTypeAsWritten())) S = '(' + S + ')'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getPointeeTypeAsWritten(), S); } @@ -221,6 +257,7 @@ void TypePrinter::printRValueReference(const RValueReferenceType *T, if (isa<ArrayType>(T->getPointeeTypeAsWritten())) S = '(' + S + ')'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getPointeeTypeAsWritten(), S); } @@ -236,6 +273,7 @@ void TypePrinter::printMemberPointer(const MemberPointerType *T, if (isa<ArrayType>(T->getPointeeType())) S = '(' + S + ')'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getPointeeType(), S); } @@ -245,12 +283,14 @@ void TypePrinter::printConstantArray(const ConstantArrayType *T, S += llvm::utostr(T->getSize().getZExtValue()); S += ']'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getElementType(), S); } void TypePrinter::printIncompleteArray(const IncompleteArrayType *T, std::string &S) { S += "[]"; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getElementType(), S); } @@ -276,6 +316,7 @@ void TypePrinter::printVariableArray(const VariableArrayType *T, } S += ']'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getElementType(), S); } @@ -291,6 +332,7 @@ void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T, } S += ']'; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getElementType(), S); } @@ -518,6 +560,7 @@ void TypePrinter::printUnaryTransform(const UnaryTransformType *T, if (!S.empty()) S = ' ' + S; std::string Str; + IncludeStrongLifetimeRAII Strong(Policy); print(T->getBaseType(), Str); switch (T->getUTTKind()) { @@ -552,6 +595,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { Buffer += "<anonymous>"; } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { + IncludeStrongLifetimeRAII Strong(Policy); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( @@ -642,6 +686,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { Args = TemplateArgs.data(); NumArgs = TemplateArgs.size(); } + IncludeStrongLifetimeRAII Strong(Policy); Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy); @@ -677,18 +722,21 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T, void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, std::string &S) { + IncludeStrongLifetimeRAII Strong(Policy); print(T->getReplacementType(), S); } void TypePrinter::printSubstTemplateTypeParmPack( const SubstTemplateTypeParmPackType *T, std::string &S) { + IncludeStrongLifetimeRAII Strong(Policy); printTemplateTypeParm(T->getReplacedParameter(), S); } void TypePrinter::printTemplateSpecialization( const TemplateSpecializationType *T, std::string &S) { + IncludeStrongLifetimeRAII Strong(Policy); std::string SpecString; { @@ -765,6 +813,7 @@ void TypePrinter::printDependentName(const DependentNameType *T, std::string &S) void TypePrinter::printDependentTemplateSpecialization( const DependentTemplateSpecializationType *T, std::string &S) { + IncludeStrongLifetimeRAII Strong(Policy); std::string MyString; { llvm::raw_string_ostream OS(MyString); @@ -796,8 +845,9 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T, void TypePrinter::printAttributed(const AttributedType *T, std::string &S) { - // Prefer the macro forms of the GC qualifiers. - if (T->getAttrKind() == AttributedType::attr_objc_gc) + // Prefer the macro forms of the GC and lifetime qualifiers. + if (T->getAttrKind() == AttributedType::attr_objc_gc || + T->getAttrKind() == AttributedType::attr_objc_lifetime) return print(T->getEquivalentType(), S); print(T->getModifiedType(), S); @@ -866,6 +916,18 @@ void TypePrinter::printAttributed(const AttributedType *T, break; } + case AttributedType::attr_objc_lifetime: + S += "objc_lifetime("; + switch (T->getEquivalentType().getObjCLifetime()) { + case Qualifiers::OCL_None: llvm_unreachable("no lifetime!"); break; + case Qualifiers::OCL_ExplicitNone: S += "none"; break; + case Qualifiers::OCL_Strong: S += "strong"; break; + case Qualifiers::OCL_Weak: S += "weak"; break; + case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break; + } + S += ")"; + break; + case AttributedType::attr_noreturn: S += "noreturn"; break; case AttributedType::attr_cdecl: S += "cdecl"; break; case AttributedType::attr_fastcall: S += "fastcall"; break; @@ -1080,7 +1142,7 @@ std::string Qualifiers::getAsString() const { // prefix a space if the string is non-empty. Will not append a final // space. void Qualifiers::getAsStringInternal(std::string &S, - const PrintingPolicy&) const { + const PrintingPolicy& Policy) const { AppendTypeQualList(S, getCVRQualifiers()); if (unsigned addrspace = getAddressSpace()) { if (!S.empty()) S += ' '; @@ -1095,6 +1157,23 @@ void Qualifiers::getAsStringInternal(std::string &S, else S += "__strong"; } + if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) { + if (!S.empty() && + !(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) + S += ' '; + + switch (lifetime) { + case Qualifiers::OCL_None: llvm_unreachable("none but true"); + case Qualifiers::OCL_ExplicitNone: S += "__unsafe_unretained"; break; + case Qualifiers::OCL_Strong: + if (!Policy.SuppressStrongLifetime) + S += "__strong"; + break; + + case Qualifiers::OCL_Weak: S += "__weak"; break; + case Qualifiers::OCL_Autoreleasing: S += "__autoreleasing"; break; + } + } } std::string QualType::getAsString(const Type *ty, Qualifiers qs) { |

