From: Fariborz Jahanian Date: Thu, 11 Jul 2013 16:48:06 +0000 (+0000) Subject: ObjectiveC arc[qoi]: When due to change of certain methods' X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f92a509d870f05a0e26babd8072171957770649e;p=clang ObjectiveC arc[qoi]: When due to change of certain methods' result type, a diagnostic being issued, issue a 'note' mentioning reason behind the unexpected warning. // rdar://14121570. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186105 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9a075fe8c8..d6b42533a0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4683,6 +4683,8 @@ def note_parameter_named_here : Note< "passing argument to parameter %0 here">; def note_parameter_here : Note< "passing argument to parameter here">; +def note_method_return_type_change : Note< + "compiler has implicitly changed method %0 return type">; // C++ casts // These messages adhere to the TryCast pattern: %0 is an int specifying the diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h index 97311a0bb4..d695e33a64 100644 --- a/include/clang/Sema/Initialization.h +++ b/include/clang/Sema/Initialization.h @@ -35,6 +35,7 @@ class ParmVarDecl; class Sema; class TypeLoc; class VarDecl; +class ObjCMethodDecl; /// \brief Describes an entity that is being initialized. class InitializedEntity { @@ -78,7 +79,10 @@ public: EK_LambdaCapture, /// \brief The entity being initialized is the initializer for a compound /// literal. - EK_CompoundLiteralInit + EK_CompoundLiteralInit, + /// \brief The entity being implicitly initialized back to the formal + /// result type. + EK_RelatedResult }; private: @@ -116,6 +120,10 @@ private: /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or /// FieldDecl, respectively. DeclaratorDecl *VariableOrMember; + + /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where + /// result type was implicitly changed to accomodate ARC semantics. + ObjCMethodDecl *MethodDecl; /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the /// low bit indicating whether the parameter is "consumed". @@ -254,6 +262,15 @@ public: Result.TypeInfo = TypeInfo; return Result; } + + /// \brief Create the initialization entity for a related result. + static InitializedEntity InitializeRelatedResult(ObjCMethodDecl *MD, + QualType Type) { + InitializedEntity Result(EK_RelatedResult, SourceLocation(), Type); + Result.MethodDecl = MD; + return Result; + } + /// \brief Create the initialization entity for a base class subobject. static InitializedEntity InitializeBase(ASTContext &Context, @@ -326,6 +343,9 @@ public: /// \brief Retrieve the variable, parameter, or field being /// initialized. DeclaratorDecl *getDecl() const; + + /// \brief Retrieve the ObjectiveC method being initialized. + ObjCMethodDecl *getMethodDecl() const { return MethodDecl; } /// \brief Determine whether this initialization allows the named return /// value optimization, which also applies to thrown objects. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 96291923bd..1898a15930 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2495,6 +2495,7 @@ DeclarationName InitializedEntity::getName() const { case EK_ComplexElement: case EK_BlockElement: case EK_CompoundLiteralInit: + case EK_RelatedResult: return DeclarationName(); } @@ -2522,6 +2523,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_BlockElement: case EK_LambdaCapture: case EK_CompoundLiteralInit: + case EK_RelatedResult: return 0; } @@ -2547,6 +2549,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_ComplexElement: case EK_BlockElement: case EK_LambdaCapture: + case EK_RelatedResult: break; } @@ -2568,6 +2571,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { case EK_New: OS << "New"; break; case EK_Temporary: OS << "Temporary"; break; case EK_CompoundLiteralInit: OS << "CompoundLiteral";break; + case EK_RelatedResult: OS << "RelatedResult"; break; case EK_Base: OS << "Base"; break; case EK_Delegating: OS << "Delegating"; break; case EK_ArrayElement: OS << "ArrayElement " << Index; break; @@ -4632,6 +4636,7 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Passing; case InitializedEntity::EK_Result: + case InitializedEntity::EK_RelatedResult: return Sema::AA_Returning; case InitializedEntity::EK_Temporary: @@ -4672,6 +4677,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_RelatedResult: return true; } @@ -4699,6 +4705,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: return true; } @@ -4781,6 +4788,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: return Initializer->getLocStart(); } llvm_unreachable("missed an InitializedEntity kind?"); @@ -5001,6 +5009,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S, else S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here); } + else if (Entity.getKind() == InitializedEntity::EK_RelatedResult && + Entity.getMethodDecl()) + S.Diag(Entity.getMethodDecl()->getLocation(), + diag::note_method_return_type_change) + << Entity.getMethodDecl()->getDeclName(); } static bool isReferenceBinding(const InitializationSequence::Step &s) { @@ -5016,6 +5029,7 @@ static bool isExplicitTemporary(const InitializedEntity &Entity, switch (Entity.getKind()) { case InitializedEntity::EK_Temporary: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: break; default: return false; @@ -5186,6 +5200,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { case InitializedEntity::EK_Temporary: case InitializedEntity::EK_LambdaCapture: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: // The entity being initialized might not outlive the full-expression. return false; } @@ -5232,6 +5247,7 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity, case InitializedEntity::EK_Temporary: case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: // We don't yet know the storage duration of the surrounding temporary. // Assume it's got full-expression duration for now, it will patch up our // storage duration if that's not correct. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 8572861988..107eed35a0 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2710,11 +2710,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If we have a related result type, we need to implicitly // convert back to the formal result type. We can't pretend to // initialize the result again --- we might end double-retaining - // --- so instead we initialize a notional temporary; this can - // lead to less-than-great diagnostics, but this stage is much - // less likely to fail than the previous stage. + // --- so instead we initialize a notional temporary. if (!RelatedRetType.isNull()) { - Entity = InitializedEntity::InitializeTemporary(FnRetType); + Entity = InitializedEntity::InitializeRelatedResult(getCurMethodDecl(), + FnRetType); Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp); if (Res.isInvalid()) { // FIXME: Clean up temporaries here anyway? diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m index 50aaf2da4d..6fa27b02fa 100644 --- a/test/SemaObjC/related-result-type-inference.m +++ b/test/SemaObjC/related-result-type-inference.m @@ -173,9 +173,9 @@ void test_inference() { @interface Fail @end @protocol X @end @implementation Fail -- (id) initWithX +- (id) initWithX // expected-note {{compiler has implicitly changed method 'initWithX' return type}} { - return (id)self; // expected-warning {{casting 'Fail *' to incompatible type 'id'}} + return (id)self; // expected-warning {{returning 'Fail *' from a function with incompatible result type 'id'}} } @end @@ -184,3 +184,19 @@ void test_inference() { @interface WeirdNSString : NSString - (id)initWithCString:(const char*)string, void *blah; @end + + +// rdar://14121570 +@protocol PMFilterManager +@end + +@interface UIViewController : NSObject +@end + +@implementation UIViewController ++ (UIViewController *)newFilterViewControllerForType // expected-note {{compiler has implicitly changed method 'newFilterViewControllerForType' return type}} +{ + UIViewController *filterVC; + return filterVC; // expected-warning {{incompatible pointer types returning 'UIViewController *' from a function with result type 'UIViewController *'}} +} +@end