From: Douglas Gregor Date: Tue, 26 Apr 2011 23:16:46 +0000 (+0000) Subject: When computing Objective-C pointer conversions in C++, retain X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=028ea4bf0c643e0e2a8fa086c28beb0d5b594ba7;p=clang When computing Objective-C pointer conversions in C++, retain the qualifiers (e.g., GC qualifiers) on the type we're converting from, rather than just blindly adopting the qualifiers of the type we're converting to or dropping qualifiers altogether. As an added bonus, properly diagnose GC qualifier mismatches to eliminate a crash in the overload resolution failure diagnostics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130255 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d690358070..f35d5c4b9b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1483,6 +1483,15 @@ def note_ovl_candidate_bad_addrspace : Note<"candidate " "constructor (inherited)}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) is in " "address space %3, but parameter must be in address space %4">; +def note_ovl_candidate_bad_gc : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "function (the implicit copy assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " + "lifetime, but parameter has %select{no|__weak|__strong}4 lifetime">; def note_ovl_candidate_bad_cvr_this : Note<"candidate " "%select{|function|||function||||" "function (the implicit copy assignment operator)|}0 not viable: " diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6e6bf22be0..7eb89787f9 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1205,6 +1205,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Pointer conversions (C++ 4.10). SCS.Second = ICK_Pointer_Conversion; SCS.IncompatibleObjC = IncompatibleObjC; + FromType = FromType.getUnqualifiedType(); } else if (S.IsMemberPointerConversion(From, FromType, ToType, InOverloadResolution, FromType)) { // Pointer to member conversions (4.11). @@ -1671,6 +1672,20 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return false; } + +/// \brief Adopt the given qualifiers for the given type. +static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){ + Qualifiers TQs = T.getQualifiers(); + + // Check whether qualifiers already match. + if (TQs == Qs) + return T; + + if (Qs.compatiblyIncludes(TQs)) + return Context.getQualifiedType(T, Qs); + + return Context.getQualifiedType(T.getUnqualifiedType(), Qs); +} /// isObjCPointerConversion - Determines whether this is an /// Objective-C pointer conversion. Subroutine of IsPointerConversion, @@ -1681,6 +1696,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, if (!getLangOptions().ObjC1) return false; + // The set of qualifiers on the type we're converting from. + Qualifiers FromQualifiers = FromType.getQualifiers(); + // First, we handle all conversions on ObjC object pointer types. const ObjCObjectPointerType* ToObjCPtr = ToType->getAs(); @@ -1694,10 +1712,11 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, FromObjCPtr->getPointeeType())) return false; + // Check for compatible // Objective C++: We're able to convert between "id" or "Class" and a // pointer to any interface (in both directions). if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) { - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } // Conversions with Objective-C's id<...>. @@ -1705,7 +1724,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ToObjCPtr->isObjCQualifiedIdType()) && Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) { - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } // Objective C++: We're able to convert from a pointer to an @@ -1720,6 +1739,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), ToType, Context); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } @@ -1731,6 +1751,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), ToType, Context); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } } @@ -1743,7 +1764,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // Objective C++: We're able to convert from a pointer to any object // to a block pointer type. if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) { - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } ToPointeeType = ToBlockPtr->getPointeeType(); @@ -1752,7 +1773,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { // Objective C++: We're able to convert from a block pointer type to a // pointer to any object. - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } else @@ -1775,6 +1796,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // We always complain about this conversion. IncompatibleObjC = true; ConvertedType = Context.getPointerType(ConvertedType); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } // Allow conversion of pointee being objective-c pointer to another one; @@ -1784,6 +1806,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, IncompatibleObjC)) { ConvertedType = Context.getPointerType(ConvertedType); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } @@ -1844,7 +1867,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, if (HasObjCConversion) { // We had an Objective-C conversion. Allow this pointer // conversion, but complain about it. - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); IncompatibleObjC = true; return true; } @@ -6541,6 +6564,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy + << FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr() + << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); assert(CVR && "unexpected qualifiers mismatch"); diff --git a/test/SemaObjCXX/overload-gc.mm b/test/SemaObjCXX/overload-gc.mm new file mode 100644 index 0000000000..afc6b96812 --- /dev/null +++ b/test/SemaObjCXX/overload-gc.mm @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-gc -fobjc-nonfragile-abi -verify %s + +void f0(__weak id *); // expected-note{{candidate function not viable: 1st argument ('id *') has no lifetime, but parameter has __weak lifetime}} + +void test_f0(id *x) { + f0(x); // expected-error{{no matching function for call to 'f0'}} +} + +@interface A +@end + +void f1(__weak id*); +void test_f1(__weak A** a) { + f1(a); +} + +@interface B : A +@end + +void f2(__weak A**); +void test_f2(__weak B** b) { + f2(b); +} +