]> granicus.if.org Git - clang/commitdiff
Adds support for ObjC++'s GC attribute on declaration of
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 19 May 2010 21:37:30 +0000 (21:37 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 19 May 2010 21:37:30 +0000 (21:37 +0000)
object variables and functions returning such objects.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104168 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/SemaDecl.cpp
test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm [new file with mode: 0644]

index d1646e00d63d7b7b613a8207f484069d9442a8ec..c9e27db566d560555c81e7841d3a9b9cda3a3fa5 100644 (file)
@@ -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)
index 11b4546e37c24aa7ae00dc8c25971b5e2bc69b77..23478e4f3c9e9d3f0e31cf17831782d5bfbf66b6 100644 (file)
@@ -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
 //===----------------------------------------------------------------------===//
index 5ea7af7144fa953bc3ecd7dfd3775713a196e14f..e0151d310100e1f071ea1620d5df21852fbf7bd5 100644 (file)
@@ -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/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm b/test/SemaObjCXX/objc2-merge-gc-attribue-decl.mm
new file mode 100644 (file)
index 0000000..7be5f17
--- /dev/null
@@ -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}}