diff options
| -rw-r--r-- | clang/include/clang/AST/ASTContext.h | 2 | ||||
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 81 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 17 | ||||
| -rw-r--r-- | clang/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm | 51 | 
4 files changed, 148 insertions, 3 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d1646e00d63..c9e27db566d 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1193,6 +1193,8 @@ public:    // Functions for calculating composite types    QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false);    QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false); +   +  QualType mergeObjCGCQualifiers(QualType, QualType);    /// UsualArithmeticConversionsType - handles the various conversions    /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 11b4546e37c..23478e4f3c9 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4661,6 +4661,87 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,    return QualType();  } +/// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and +/// 'RHS' attributes and returns the merged version; including for function +/// return types. +QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { +  QualType LHSCan = getCanonicalType(LHS), +  RHSCan = getCanonicalType(RHS); +  // If two types are identical, they are compatible. +  if (LHSCan == RHSCan) +    return LHS; +  if (RHSCan->isFunctionType()) { +    if (!LHSCan->isFunctionType()) +      return QualType(); +    QualType OldReturnType =  +      cast<FunctionType>(RHSCan.getTypePtr())->getResultType(); +    QualType NewReturnType = +      cast<FunctionType>(LHSCan.getTypePtr())->getResultType(); +    QualType ResReturnType =  +      mergeObjCGCQualifiers(NewReturnType, OldReturnType); +    if (ResReturnType.isNull()) +      return QualType(); +    if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) { +      // id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo(); +      // In either case, use OldReturnType to build the new function type. +      const FunctionType *F = LHS->getAs<FunctionType>(); +      if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { +        FunctionType::ExtInfo Info = getFunctionExtInfo(LHS); +        QualType ResultType +          = getFunctionType(OldReturnType, FPT->arg_type_begin(), +                                  FPT->getNumArgs(), FPT->isVariadic(), +                                  FPT->getTypeQuals(), +                                  FPT->hasExceptionSpec(), +                                  FPT->hasAnyExceptionSpec(), +                                  FPT->getNumExceptions(), +                                  FPT->exception_begin(), +                                  Info); +        return ResultType; +      } +    } +    return QualType(); +  } +   +  // If the qualifiers are different, the types can still be merged. +  Qualifiers LQuals = LHSCan.getLocalQualifiers(); +  Qualifiers RQuals = RHSCan.getLocalQualifiers(); +  if (LQuals != RQuals) { +    // If any of these qualifiers are different, we have a type mismatch. +    if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || +        LQuals.getAddressSpace() != RQuals.getAddressSpace()) +      return QualType(); +     +    // Exactly one GC qualifier difference is allowed: __strong is +    // okay if the other type has no GC qualifier but is an Objective +    // C object pointer (i.e. implicitly strong by default).  We fix +    // this by pretending that the unqualified type was actually +    // qualified __strong. +    Qualifiers::GC GC_L = LQuals.getObjCGCAttr(); +    Qualifiers::GC GC_R = RQuals.getObjCGCAttr(); +    assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); +     +    if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) +      return QualType(); +     +    if (GC_L == Qualifiers::Strong) +      return LHS; +    if (GC_R == Qualifiers::Strong) +      return RHS; +    return QualType(); +  } +   +  if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) { +    QualType LHSBaseQT = LHS->getAs<ObjCObjectPointerType>()->getPointeeType(); +    QualType RHSBaseQT = RHS->getAs<ObjCObjectPointerType>()->getPointeeType(); +    QualType ResQT = mergeObjCGCQualifiers(LHSBaseQT, RHSBaseQT); +    if (ResQT == LHSBaseQT) +      return LHS; +    if (ResQT == RHSBaseQT) +      return RHS; +  } +  return QualType(); +} +  //===----------------------------------------------------------------------===//  //                         Integer Predicates  //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5ea7af7144f..e0151d31010 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1077,10 +1077,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {        = cast<FunctionType>(OldQType.getTypePtr())->getResultType();      QualType NewReturnType        = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); +    QualType ResQT;      if (OldReturnType != NewReturnType) { -      Diag(New->getLocation(), diag::err_ovl_diff_return_type); -      Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); -      return true; +      if (NewReturnType->isObjCObjectPointerType() +          && OldReturnType->isObjCObjectPointerType()) +        ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); +      if (ResQT.isNull()) { +        Diag(New->getLocation(), diag::err_ovl_diff_return_type); +        Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); +        return true; +      } +      else +        NewQType = ResQT;      }      const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); @@ -1364,6 +1372,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {          = Context.getCanonicalType(New->getType())->getAs<ArrayType>();        if (OldArray->getElementType() == NewArray->getElementType())          MergedT = Old->getType(); +    } else if (New->getType()->isObjCObjectPointerType() +               && Old->getType()->isObjCObjectPointerType()) { +        MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType());      }    } else {      MergedT = Context.mergeTypes(New->getType(), Old->getType()); diff --git a/clang/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm b/clang/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm new file mode 100644 index 00000000000..7be5f17daa8 --- /dev/null +++ b/clang/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-gc -fsyntax-only -verify %s +@interface INTF @end + +extern INTF* p2; +extern __strong INTF* p2; + +extern __strong id p1; +extern id p1; + +extern id CFRunLoopGetMain(); +extern __strong id CFRunLoopGetMain(); + +extern __strong id CFRunLoopGetMain2(); +extern id CFRunLoopGetMain2(); + +extern INTF* CFRunLoopGetMain3(); +extern __strong INTF* CFRunLoopGetMain3(); + +extern __strong INTF* CFRunLoopGetMain4(); +extern INTF* CFRunLoopGetMain4(); + +typedef id ID; +extern ID CFRunLoopGetMain5(); +extern __strong id CFRunLoopGetMain5(); + +extern __strong id CFRunLoopGetMain6(); +extern ID CFRunLoopGetMain6(); + +extern ID CFRunLoopGetMain7(); +extern __strong ID CFRunLoopGetMain7(); + +extern __strong ID CFRunLoopGetMain8(); +extern ID CFRunLoopGetMain8(); + +extern __weak id WLoopGetMain(); // expected-note {{previous declaration is here}} +extern id WLoopGetMain();	// expected-error {{functions that differ only in their return type cannot be overloaded}} + +extern id p3;	// expected-note {{previous definition is here}} +extern __weak id p3;	// expected-error {{redefinition of 'p3' with a different type}} + +extern void *p4; // expected-note {{previous definition is here}} +extern void * __strong p4; // expected-error {{redefinition of 'p4' with a different type}} + +extern id p5; +extern __strong id p5; + +extern char* __strong p6; // expected-note {{previous definition is here}} +extern char* p6; // expected-error {{redefinition of 'p6' with a different type}} + +extern __strong char* p7; // expected-note {{previous definition is here}} +extern char* p7; // expected-error {{redefinition of 'p7' with a different type}}  | 

