[cfe-commits] r75314 - in /cfe/trunk: include/clang/AST/ include/clang/Analysis/PathSensitive/ lib/AST/ lib/Analysis/ lib/CodeGen/ lib/Frontend/ lib/Sema/ test/CodeGenObjC/ test/PCH/ test/SemaObjC/ test/SemaObjCXX/
Chris Lattner
clattner at apple.com
Sun Jul 12 23:00:39 PDT 2009
On Jul 10, 2009, at 4:35 PM, Steve Naroff wrote:
> Author: snaroff
> Date: Fri Jul 10 18:34:53 2009
> New Revision: 75314
>
> URL: http://llvm.org/viewvc/llvm-project?rev=75314&view=rev
> Log:
> This patch includes a conceptually simple, but very intrusive/
> pervasive change.
Yay, thanks for working on this. Does this add support for Class<x>
and friends? If so, please add testcases.
...
> class ObjCObjectPointerType : public Type, public
> llvm::FoldingSetNode {
> QualType PointeeType; // will always point to an interface type.
>
> // List of protocols for this protocol conforming object type
> // List is sorted on protocol name. No protocol is entered more
> than once.
> llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;
>
> ObjCObjectPointerType(QualType T, ObjCProtocolDecl **Protos,
> unsigned NumP) :
> Type(ObjCObjectPointer, QualType(), /*Dependent=*/false),
> PointeeType(T), Protocols(Protos, Protos+NumP) { }
> friend class ASTContext; // ASTContext creates these.
> friend class ObjCInterfaceType; // To enable 'id' and 'Class'
> predicates.
>
> static ObjCInterfaceType *IdInterfaceT;
> static ObjCInterfaceType *ClassInterfaceT;
> static void setIdInterface(QualType T) {
Please don't use static members within the class. This is not safe
when there are multiple translation units open at a time and when
threading is happening. Please put state like this in ASTContext.
> @@ -3198,8 +3186,30 @@
> /// compatible for assignment from RHS to LHS. This handles
> validation of any
> /// protocol qualifiers on the LHS or RHS.
> ///
> +/// FIXME: Move the following to ObjCObjectPointerType/
> ObjCInterfaceType.
> +bool ASTContext::canAssignObjCInterfaces(const
> ObjCObjectPointerType *LHSOPT,
> + const
> ObjCObjectPointerType *RHSOPT) {
> + // If either interface represents the built-in 'id' or 'Class'
> types,
> + // then return true (no need to call canAssignObjCInterfaces()).
> + if (LHSOPT->isObjCIdType() || RHSOPT->isObjCIdType() ||
> + LHSOPT->isObjCClassType() || RHSOPT->isObjCClassType())
> + return true;
It seems common to check for "isObjCIdType || isObjCClassType" and:
> bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
> const ObjCInterfaceType
> *RHS) {
> + // If either interface represents the built-in 'id' or 'Class'
> types,
> + // then return true.
> + if (LHS->isObjCIdInterface() || RHS->isObjCIdInterface() ||
> + LHS->isObjCClassInterface() || RHS->isObjCClassInterface())
"isObjCIdInterface || isObjCClassInterface"
Does it make sense to add direct predicates for these?
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Jul 10 18:34:53 2009
> @@ -382,7 +382,8 @@
> const Expr* SubExpr = E->getSubExpr();
>
> // Check for pointer->pointer cast
> - if (SubExpr->getType()->isPointerType()) {
> + if (SubExpr->getType()->isPointerType() ||
> + SubExpr->getType()->isObjCObjectPointerType()) {
Would it make sense to add a "isAnyPointerType()" method to do both
these checks?
> +++ cfe/trunk/lib/Analysis/BasicObjCFoundationChecks.cpp Fri Jul 10
> 18:34:53 2009
I'll let Ted review libanalysis and friends.
> +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Fri Jul 10 18:34:53 2009
> @@ -761,8 +761,10 @@
> // Unsupported types
> return llvm::DIType();
> case Type::ObjCObjectPointer: // Encode id<p> in debug info just
> like id.
> - return Slot = getOrCreateType(M->getContext().getObjCIdType(),
> Unit);
> -
> + {
> + ObjCObjectPointerType *OPT = cast<ObjCObjectPointerType>(Ty);
> + return Slot = CreateType(OPT->getInterfaceType(), Unit);
> + }
I don't think this is right. Given something like id<foo>, this
should call CreateType on "id". Given NSString<foo> it should call
CreateType on "NSString*", not "NSString".
> +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Fri Jul 10 18:34:53 2009
> @@ -987,7 +987,7 @@
> }
>
> Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
> - if (!Ops.Ty->isPointerType()) {
> + if (!Ops.Ty->isPointerType() && !Ops.Ty-
> >isObjCObjectPointerType()) {
Another candidate for "isAnyPointerType"? What happens when you add
an objc pointer to an integer? Isn't it the same as adding to a
pointer to struct? It seems that this code could be merged now.
> +++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Fri Jul 10 18:34:53 2009
> @@ -215,6 +215,7 @@
> const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
> const clang::Type &Ty = *Context.getCanonicalType(T);
>
> + //T->dump();
Please remove.
> switch (Ty.getTypeClass()) {
> #define TYPE(Class, Base)
> #define ABSTRACT_TYPE(Class, Base)
> @@ -353,10 +354,14 @@
> return T;
> }
>
> - case Type::ObjCObjectPointer:
> - // Protocols don't influence the LLVM type.
> - return ConvertTypeRecursive(Context.getObjCIdType());
> -
> + case Type::ObjCObjectPointer: {
> + // Qualified id types don't influence the LLVM type, here we
> always return
> + // an opaque type for 'id'.
> + const llvm::Type *&T = InterfaceTypes[0];
> + if (!T)
> + T = llvm::OpaqueType::get();
> + return llvm::PointerType::getUnqual(T);
> + }
This doesn't seem like the right thing, can you check with Daniel on
this?
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jul 10 18:34:53 2009
> @@ -527,13 +525,15 @@
> case 2:
> if (!TypeID->isStr("id"))
> break;
> - Context.setObjCIdType(Context.getTypeDeclType(New));
> - objc_types = true;
> + // Install the built-in type for 'id', ignoring the current
> definition.
> + New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
> + return;
> break;
Please remove the dead break.
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Jul 10 18:34:53 2009
> @@ -1844,6 +1844,17 @@
> BaseExpr = RHSExp;
> IndexExpr = LHSExp;
> ResultType = PTy->getPointeeType();
> + } else if (const ObjCObjectPointerType *PTy =
> + LHSTy->getAsObjCObjectPointerType()) {
> + BaseExpr = LHSExp;
> + IndexExpr = RHSExp;
> + ResultType = PTy->getPointeeType();
> + } else if (const ObjCObjectPointerType *PTy =
> + RHSTy->getAsObjCObjectPointerType()) {
> + // Handle the uncommon case of "123[Ptr]".
> + BaseExpr = RHSExp;
> + IndexExpr = LHSExp;
> + ResultType = PTy->getPointeeType();
It seems that the objc and normal pointer type can be merged with your
new "getpointeetype" method.
> @@ -2212,12 +2225,71 @@
> << DeclarationName(&Member) << int(OpKind == tok::arrow));
> }
>
> + // Handle properties on ObjC 'Class' types.
> + if (OpKind == tok::period && (BaseType->isObjCClassType())) {
It's minor, but no need for the redundant parens here.
> + // Also must look for a getter name which uses property syntax.
> + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
> + if (ObjCMethodDecl *MD = getCurMethodDecl()) {
> + ObjCInterfaceDecl *IFace = MD->getClassInterface();
> + ObjCMethodDecl *Getter;
> + // FIXME: need to also look locally in the implementation.
> + if ((Getter = IFace->lookupClassMethod(Sel))) {
> + // Check the use of this method.
> + if (DiagnoseUseOfDecl(Getter, MemberLoc))
> + return ExprError();
> + }
> + // If we found a getter then this may be a valid dot-
> reference, we
> + // will look for the matching setter, in case it is needed.
> + Selector SetterSel =
> + SelectorTable::constructSetterName(PP.getIdentifierTable(),
> + PP.getSelectorTable(),
> &Member);
> + ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
> + if (!Setter) {
> + // If this reference is in an @implementation, also check
> for 'private'
> + // methods.
> + Setter = FindMethodInNestedImplementations(IFace, SetterSel);
> + }
> + // Look through local category implementations associated
> with the class.
> + if (!Setter) {
> + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !
> Setter; i++) {
> + if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
> + Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel);
> + }
> + }
This code looks like it is something that should be factored out into
a helper method. Are there other pieces of code doing the same lookup
algorithm?
> // Handle properties on qualified "id" protocols.
> + const ObjCObjectPointerType *QIdTy;
> + if (OpKind == tok::period && (QIdTy = BaseType-
> >getAsObjCQualifiedIdType())) {
Can this be merged with the non-qualified case?
> @@ -3517,6 +3523,29 @@
> return Incompatible;
> }
>
> + if (isa<ObjCObjectPointerType>(lhsType)) {
> + if (rhsType->isIntegerType())
> + return IntToPointer;
> +
> + if (isa<PointerType>(rhsType)) {
> + QualType lhptee = lhsType->getAsObjCObjectPointerType()-
> >getPointeeType();
> + QualType rhptee = rhsType->getAsPointerType()-
> >getPointeeType();
> + return CheckPointeeTypesForAssignment(lhptee, rhptee);
Why not use lhsType->getPointeeType() (and also for rhsType)?
> + }
> + if (rhsType->isObjCObjectPointerType()) {
> + QualType lhptee = lhsType->getAsObjCObjectPointerType()-
> >getPointeeType();
> + QualType rhptee = rhsType->getAsObjCObjectPointerType()-
> >getPointeeType();
> + return CheckPointeeTypesForAssignment(lhptee, rhptee);
That would allow merging this case in as well.
> @@ -3776,12 +3823,23 @@
>
> // Put any potential pointer into PExp
> Expr* PExp = lex, *IExp = rex;
> - if (IExp->getType()->isPointerType())
> + if (IExp->getType()->isPointerType() ||
> + IExp->getType()->isObjCObjectPointerType())
->isAnyPointerType()
> std::swap(PExp, IExp);
>
> - if (const PointerType *PTy = PExp->getType()->getAsPointerType()) {
> + if (PExp->getType()->isPointerType() ||
> + PExp->getType()->isObjCObjectPointerType()) {
again.
> +
> if (IExp->getType()->isIntegerType()) {
> - QualType PointeeTy = PTy->getPointeeType();
> + QualType PointeeTy;
> + const PointerType *PTy;
> + const ObjCObjectPointerType *OPT;
> +
> + if ((PTy = PExp->getType()->getAsPointerType()))
> + PointeeTy = PTy->getPointeeType();
> + else if ((OPT = PExp->getType()->getAsObjCObjectPointerType()))
> + PointeeTy = OPT->getPointeeType();
This should be able to use QualType::getPointeeType() instead of the
if/elseif
> @@ -3855,10 +3913,16 @@
> if (CompLHSTy) *CompLHSTy = compType;
> return compType;
> }
> -
> +
> // Either ptr - int or ptr - ptr.
> - if (const PointerType *LHSPTy = lex->getType()-
> >getAsPointerType()) {
> - QualType lpointee = LHSPTy->getPointeeType();
> + if (lex->getType()->isPointerType() ||
> + lex->getType()->isObjCObjectPointerType()) {
isAnyPointerType()
> + QualType lpointee;
> + if (const PointerType *LHSPTy = lex->getType()-
> >getAsPointerType())
> + lpointee = LHSPTy->getPointeeType();
> + else if (const ObjCObjectPointerType *OPT =
> + lex->getType()->getAsObjCObjectPointerType())
> + lpointee = OPT->getPointeeType();
lex->getType()->getPointeeType()
> @@ -4226,19 +4289,27 @@
> ImpCastExprToType(rex, lType);
> return ResultTy;
> }
> + if (lType->isObjCObjectPointerType() && rType-
> >isObjCObjectPointerType()) {
> + if (!Context.areComparableObjCPointerTypes(lType, rType)) {
> + Diag(Loc,
> diag::ext_typecheck_comparison_of_distinct_pointers)
> << lType << rType << lex->getSourceRange() << rex-
> >getSourceRange();
> }
> + if (lType->isObjCQualifiedIdType() && rType-
> >isObjCQualifiedIdType()) {
> + if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
> + ImpCastExprToType(rex, lType);
> + return ResultTy;
> + } else {
> + Diag(Loc, diag::warn_incompatible_qualified_id_operands)
> + << lType << rType << lex->getSourceRange() << rex-
> >getSourceRange();
> + ImpCastExprToType(rex, lType);
> + return ResultTy;
This else case can be unnested and can fall through to share the
ImpCastExprToType + return.
> + }
> + }
> + ImpCastExprToType(rex, lType);
> + return ResultTy;
> }
> }
> - if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) &&
> + if ((lType->isPointerType() || lType->isObjCObjectPointerType()) &&
isAnyPointerType()
> @@ -4250,7 +4321,7 @@
> return ResultTy;
> }
> if (lType->isIntegerType() &&
> - (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
> + (rType->isPointerType() || rType->isObjCObjectPointerType())) {
isAnyPointerType()
> @@ -4524,9 +4594,17 @@
> Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
> } else if (ResType->isRealType()) {
> // OK!
> - } else if (const PointerType *PT = ResType->getAsPointerType()) {
> + } else if (ResType->getAsPointerType() ||ResType-
> >isObjCObjectPointerType()) {
isAnyPointerType(), please don't use "getAs" in a bool context.
> + QualType PointeeTy;
> +
> + if (const PointerType *PTy = ResType->getAsPointerType())
> + PointeeTy = PTy->getPointeeType();
> + else if (const ObjCObjectPointerType *OPT =
> + ResType->getAsObjCObjectPointerType())
> + PointeeTy = OPT->getPointeeType();
QualType::getPointeeType().
> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jul 10 18:34:53 2009
> @@ -1482,7 +1482,8 @@
> QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
> assert(getLangOptions().CPlusPlus && "This function assumes C++");
> QualType T1 = E1->getType(), T2 = E2->getType();
> - if(!T1->isPointerType() && !T2->isPointerType())
> + if(!T1->isPointerType() && !T2->isPointerType() &&
> + !T1->isObjCObjectPointerType() && !T2-
> >isObjCObjectPointerType())
isAnyPointerType()
> +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Jul 10 18:34:53 2009
wow, nice cleanups!
>
> + if (rhsOPT->qual_empty()) {
> + // If the RHS is a unqualified interface pointer "NSString*",
> + // make sure we check the class hierarchy.
> + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
> + for (ObjCObjectPointerType::qual_iterator I = lhsQID-
> >qual_begin(),
> + E = lhsQID->qual_end(); I != E; ++I) {
> + // when comparing an id<P> on lhs with a static type on
> rhs,
> + // see if static class implements all of id's protocols,
> directly or
> + // through its super class and categories.
> + if (!ClassImplementsProtocol(*I, rhsID, true))
> + return false;
> + }
> + return true;
This return can be removed.
> + }
> + // If there are no qualifiers and no interface, we have an
> 'id'.
> + return true;
> + }
> + // Both the right and left sides have qualifiers.
> for (ObjCObjectPointerType::qual_iterator I = lhsQID-
> >qual_begin(),
> E = lhsQID->qual_end(); I != E; ++I) {
> ObjCProtocolDecl *lhsProto = *I;
> @@ -803,28 +779,26 @@
> // when comparing an id<P> on lhs with a static type on rhs,
> // see if static class implements all of id's protocols,
> directly or
> // through its super class and categories.
> + for (ObjCObjectPointerType::qual_iterator J = rhsOPT-
> >qual_begin(),
> + E = rhsOPT->qual_end(); J != E; ++J) {
> + ObjCProtocolDecl *rhsProto = *J;
> if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
> (compare && ProtocolCompatibleWithProtocol(rhsProto,
> lhsProto))) {
> match = true;
> break;
> }
> }
> + // If the RHS is a qualified interface pointer "NSString<P>*",
> + // make sure we check the class hierarchy.
> + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
> + for (ObjCObjectPointerType::qual_iterator I = lhsQID-
> >qual_begin(),
> + E = lhsQID->qual_end(); I != E; ++I) {
> + // when comparing an id<P> on lhs with a static type on
> rhs,
> + // see if static class implements all of id's protocols,
> directly or
> + // through its super class and categories.
> + if (ClassImplementsProtocol(*I, rhsID, true)) {
> + match = true;
> + break;
> }
> }
Does this loop exist elsewhere? If so, please factor out to a helper
function.
> }
> @@ -837,7 +811,52 @@
>
> const ObjCObjectPointerType *rhsQID = rhs-
> >getAsObjCQualifiedIdType();
> assert(rhsQID && "One of the LHS/RHS should be id<x>");
> -
> +
> + if (const ObjCObjectPointerType *lhsOPT =
> + lhs->getAsObjCInterfacePointerType()) {
> + if (lhsOPT->qual_empty()) {
> + bool match = false;
> + if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
> + for (ObjCObjectPointerType::qual_iterator I = rhsQID-
> >qual_begin(),
> + E = rhsQID->qual_end(); I != E; ++I) {
> + // when comparing an id<P> on lhs with a static type on
> rhs,
> + // see if static class implements all of id's protocols,
> directly or
> + // through its super class and categories.
> + if (ClassImplementsProtocol(*I, lhsID, true)) {
> + match = true;
> + break;
> + }
> + }
> + if (!match)
> + return false;
Please factor the inner loop out to a helper function. This allows
you to use early return instead of the 'match' bool + break.
> + }
> + return true;
> + }
> + // Both the right and left sides have qualifiers.
> + for (ObjCObjectPointerType::qual_iterator I = lhsOPT-
> >qual_begin(),
> + E = lhsOPT->qual_end(); I != E; ++I) {
> + ObjCProtocolDecl *lhsProto = *I;
> + bool match = false;
> +
> + // when comparing an id<P> on lhs with a static type on rhs,
> + // see if static class implements all of id's protocols,
> directly or
> + // through its super class and categories.
> + for (ObjCObjectPointerType::qual_iterator J = rhsQID-
> >qual_begin(),
> + E = rhsQID->qual_end(); J != E; ++J) {
> + ObjCProtocolDecl *rhsProto = *J;
> + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
> + (compare && ProtocolCompatibleWithProtocol(rhsProto,
> lhsProto))) {
> + match = true;
> + break;
This seems very similar to the above loops, it would be nice to
commonize them somehow.
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Jul 10 18:34:53 2009
Please ask Doug to review this.
> + // Beyond this point, both types need to be C pointers or block
> pointers.
> QualType ToPointeeType;
> - const PointerType* ToTypePtr = ToType->getAsPointerType();
> - if (ToTypePtr)
> - ToPointeeType = ToTypePtr->getPointeeType();
> + if (const PointerType *ToCPtr = ToType->getAsPointerType())
> + ToPointeeType = ToCPtr->getPointeeType();
> else if (const BlockPointerType *ToBlockPtr = ToType-
> >getAsBlockPointerType())
> ToPointeeType = ToBlockPtr->getPointeeType();
> else
> return false;
These can use Type::getPointeeType(). Incidentally, please update
the comment on Type::getPointeeType() to fix it to say that it works
on block pointers. It does, but the comment says it doesn't.
>
> QualType FromPointeeType;
> - const PointerType *FromTypePtr = FromType->getAsPointerType();
> - if (FromTypePtr)
> - FromPointeeType = FromTypePtr->getPointeeType();
> - else if (const BlockPointerType *FromBlockPtr
> - = FromType->getAsBlockPointerType())
> + if (const PointerType *FromCPtr = FromType->getAsPointerType())
> + FromPointeeType = FromCPtr->getPointeeType();
> + else if (const BlockPointerType *FromBlockPtr = FromType-
> >getAsBlockPointerType())
> FromPointeeType = FromBlockPtr->getPointeeType();
> else
> return false;
These can use Type::getPointeeType().
> + if (const ObjCObjectPointerType *FromPtrType =
> + FromType->getAsObjCObjectPointerType())
> + if (const ObjCObjectPointerType *ToPtrType =
> + ToType->getAsObjCObjectPointerType()) {
> + // Objective-C++ conversions are always okay.
> + // FIXME: We should have a different class of conversions for
> the
> + // Objective-C++ implicit conversions.
> + if (FromPtrType->isObjCIdType() || ToPtrType->isObjCIdType() ||
> + FromPtrType->isObjCClassType() || ToPtrType-
> >isObjCClassType())
Can use some sort of merged predicate for isObjCIdType ||
isObjCClassType.
>
> +++ cfe/trunk/test/CodeGenObjC/encode-test.m Fri Jul 10 18:34:53 2009
> @@ -1,7 +1,7 @@
> // RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-
> llvm -o %t %s &&
> // RUN: grep -e "\^{Innermost=CC}" %t | count 1 &&
> -// RUN: grep -e "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count
> 1 &&
> -// RUN: grep -e "{B1=#@c}" %t | count 1 &&
> +// RUN: grep -e "{Derived=^{objc_class}ib32b8b3b8sb16b8b8b2b8ccb6}"
> %t | count 1 &&
> +// RUN: grep -e "{B1=^{objc_class}@c}" %t | count 1 &&
> // RUN: grep -e "v12 at 0:4\[3\[4@]]8" %t | count 1 &&
> // RUN: grep -e "r\^{S=i}" %t | count 1 &&
> // RUN: grep -e "\^{Object=#}" %t | count 1
The output of @encode changed? Isn't this an ABI bug??
> +++ cfe/trunk/test/CodeGenObjC/overloadable.m Fri Jul 10 18:34:53 2009
> @@ -3,8 +3,8 @@
>
> @class C;
>
> -// RUN: grep _Z1fP11objc_object %t | count 1 &&
> -void __attribute__((overloadable)) f(C *c) { }
> +// RUN: grep _Z1fP2id %t | count 1 &&
> +void __attribute__((overloadable)) f(id c) { }
>
> // RUN: grep _Z1fP1C %t | count 1
> -void __attribute__((overloadable)) f(id c) { }
> +void __attribute__((overloadable)) f(C *c) { }
Likewise, mangling changing sounds like a serious ABI bug.
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/test/PCH/objc_exprs.m (original)
> +++ cfe/trunk/test/PCH/objc_exprs.m Fri Jul 10 18:34:53 2009
> @@ -6,7 +6,7 @@
> // RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s
>
> // Expressions
> -int *A1 = (objc_string)0; // expected-warning {{'struct
> objc_object *'}}
> +int *A1 = (objc_string)0; // expected-warning {{aka 'id'}}
Nice.
> +++ cfe/trunk/test/SemaObjC/comptypes-5.m Fri Jul 10 18:34:53 2009
> @@ -26,8 +26,8 @@
> MyOtherClass<MyProtocol> *obj_c_super_p_q = nil;
> MyClass<MyProtocol> *obj_c_cat_p_q = nil;
>
> - obj_c_cat_p = obj_id_p; // expected-warning {{incompatible type
> assigning 'id<MyProtocol>', expected 'MyClass *'}}
> - obj_c_super_p = obj_id_p; // expected-warning {{incompatible
> type assigning 'id<MyProtocol>', expected 'MyOtherClass *'}}
> + obj_c_cat_p = obj_id_p;
> + obj_c_super_p = obj_id_p;
Is this supposed to be allowed?
> +++ cfe/trunk/test/SemaObjC/conditional-expr-3.m Fri Jul 10 18:34:53
> 2009
> @@ -59,7 +59,7 @@
> }
>
> void f10(int cond, id<P0,P1> x0, id<P0,P2> x1) {
> - barP2(cond ? x0 : x1);
> + barP2(cond ? x0 : x1); // expected-warning {{incompatible type
> passing 'id<P0,P1>', expected 'id<P2>'}}
Shouldn't the merged type of ?: be id<P0> here, not id<P0,P1> ?
> +++ cfe/trunk/test/SemaObjC/message.m Fri Jul 10 18:34:53 2009
> @@ -95,6 +95,6 @@
> void foo4() {
> struct objc_object X[10];
>
> - [X rect];
> + [(id)X rect];
> }
This is a bug, we should be performing unary "array -> pointer" decay
here. This was in response to a bugzilla, we need to support this.
> +++ cfe/trunk/test/SemaObjCXX/overload.mm Fri Jul 10 18:34:53 2009
> @@ -1,4 +1,5 @@
> // RUN: clang-cc -fsyntax-only -verify %s
> +// XFAIL
> @interface Foo
> @end
What is the problem with this test?
Thanks again for working on this Steve! I know it's largely
thankless, but it's a huge cleanup.
-Chris
More information about the cfe-commits
mailing list