Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -112,6 +112,10 @@ ; } +- ``-Wobjc-encodings-larger-than=`` is a new diagnostic that diagnoses when the Objective + C runtime is generating large Objective C runtime information. This often happens + when passing C++ classes in Objective C messages/blocks. This information can get very + large. A good starting value is 1024 (1K). Non-comprehensive list of changes in this release ------------------------------------------------- Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -397,6 +397,8 @@ def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">; +def ObjCEncodingLargerThan : DiagGroup<"objc-encoding-larger-than=">; + def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6203,6 +6203,15 @@ InGroup>; def note_objc_unsafe_perform_selector_method_declared_here : Note< "method %0 that returns %1 declared here">; +def warn_objc_method_encoding_too_large : Warning< + "%0 method %1 encoding of size %2 is larger than %3 bytes">, + InGroup; +def warn_objc_block_encoding_too_large : Warning< + "block argument encoding of size %0 is larger than %1 bytes">, + InGroup; +def warn_objc_ivar_encoding_too_large : Warning< + "instance variable encoding of size %0 is larger than %1 bytes">, + InGroup; def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -99,6 +99,8 @@ "Encoding extended block type signature") BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1, "Objective-C related result type inference") +BENIGN_LANGOPT(ObjCLargeEncodingSize, 32, 0, + "if non-zero, warn about Objective-C encodings larger in bytes than this setting. 0 is no check.") LANGOPT(AppExt , 1, 0, "Objective-C App Extension") LANGOPT(Trigraphs , 1, 0,"trigraphs") LANGOPT(LineComment , 1, 0, "'//' comments") Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1698,6 +1698,8 @@ def Wlarger_than_ : Joined<["-"], "Wlarger-than-">, Alias; def Wframe_larger_than_EQ : Joined<["-"], "Wframe-larger-than=">, Group, Flags<[DriverOption]>; +def Wobjc_encoding_larger_than_EQ : Joined<["-"], "Wobjc-encoding-larger-than=">, Flags<[CC1Option]>; + def : Flag<["-"], "fterminated-vtables">, Alias; def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group; def ftime_report : Flag<["-"], "ftime-report">, Group, Flags<[CC1Option]>; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1711,6 +1711,7 @@ DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); void DiagnoseUseOfUnimplementedSelectors(); + void DiagnoseLargeIvarEncodings(ObjCImplementationDecl *ID); bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4232,6 +4232,14 @@ CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_Wobjc_encoding_larger_than_EQ)) { + if (A->getNumValues()) { + StringRef bytes = A->getValue(); + CmdArgs.push_back( + Args.MakeArgString("-Wobjc-encoding-larger-than=" + bytes)); + } + } + if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, options::OPT_Wlarge_by_value_copy_def)) { if (A->getNumValues()) { Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2656,6 +2656,8 @@ Args.getLastArgValue(OPT_fconstant_string_class); Opts.ObjCDefaultSynthProperties = !Args.hasArg(OPT_disable_objc_default_synthesize_properties); + Opts.ObjCLargeEncodingSize = + getLastArgIntValue(Args, OPT_Wobjc_encoding_larger_than_EQ, 0, Diags); Opts.EncodeExtendedBlockSig = Args.hasArg(OPT_fencode_extended_block_signature); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Index: lib/Sema/SemaDeclObjC.cpp =================================================================== --- lib/Sema/SemaDeclObjC.cpp +++ lib/Sema/SemaDeclObjC.cpp @@ -3875,6 +3875,25 @@ } } +// Run through the ivars and see if any of their encodings are larger than +// ObjCLargeEncodingSize. +void Sema::DiagnoseLargeIvarEncodings(ObjCImplementationDecl *ID) { + unsigned long encodingSize = LangOpts.ObjCLargeEncodingSize; + if (encodingSize == 0) return; + + for (ObjCIvarDecl *ivar = ID->getClassInterface()->all_declared_ivar_begin(); + ivar; ivar = ivar->getNextIvar()) { + QualType QT = Context.getBaseElementType(ivar->getType()); + std::string encoding; + QualType NotEncodedT; + Context.getObjCEncodingForType(QT, encoding, nullptr, &NotEncodedT); + if (encoding.length() > encodingSize) { + Diag(ivar->getLocation(), diag::warn_objc_ivar_encoding_too_large) + << (unsigned)encoding.length() << (unsigned)encodingSize; + } + } +} + // Note: For class/category implementations, allMethods is always null. Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, ArrayRef allTUVars) { @@ -4006,6 +4025,7 @@ if (IDecl->hasDesignatedInitializers()) DiagnoseMissingDesignatedInitOverrides(IC, IDecl); DiagnoseWeakIvars(*this, IC); + DiagnoseLargeIvarEncodings(IC); DiagnoseRetainableFlexibleArrayMember(*this, IDecl); bool HasRootClassAttr = IDecl->hasAttr(); @@ -4768,6 +4788,15 @@ } } + /// Check for method encoding size. + std::string encoding = Context.getObjCEncodingForMethodDecl(ObjCMethod); + unsigned long encodingSize = LangOpts.ObjCLargeEncodingSize; + if (encodingSize && encoding.length() > encodingSize) { + Diag(ObjCMethod->getLocation(), diag::warn_objc_method_encoding_too_large) + << (ObjCMethod->isInstanceMethod() ? "instance" : "class") + << ObjCMethod->getDeclName() << (unsigned)encoding.length() + << (unsigned)encodingSize; + } ActOnDocumentableDecl(ObjCMethod); return ObjCMethod; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13777,6 +13777,16 @@ if (getCurFunction()) getCurFunction()->addBlock(BD); + /// Check for block objective C encoding size + if (getLangOpts().ObjC) { + std::string encoding = Context.getObjCEncodingForBlock(Result); + unsigned long encodingSize = LangOpts.ObjCLargeEncodingSize; + if (encodingSize && encoding.length() > encodingSize) { + Diag(BD->getLocation(), diag::warn_objc_block_encoding_too_large) + << (unsigned)encoding.length() << (unsigned)encodingSize; + } + } + return Result; } Index: test/SemaObjC/objc-large-encoding-warn.m =================================================================== --- test/SemaObjC/objc-large-encoding-warn.m +++ test/SemaObjC/objc-large-encoding-warn.m @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -Wobjc-encoding-larger-than=10 -Wno-objc-root-class %s + +struct MyStruct { + int a; + int b; + struct MyStruct *c; +}; + +@interface MyClass { + struct MyStruct iVarThatWarns; // expected-warning {{instance variable encoding of size 24 is larger than 10 bytes}} +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-encoding-larger-than=" + struct MyStruct iVarThatDoesntWarn; +#pragma clang diagnostic pop + id idThatDoesntWarn; +} +@end + +@implementation MyClass +- (void)methodThatWarns:(struct MyStruct)aStruct {} // expected-warning {{instance method 'methodThatWarns:' encoding of size 33 is larger than 10 bytes}} +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-encoding-larger-than=" +- (void)methodThatDoesntWarn:(struct MyStruct)aStruct {} +#pragma clang diagnostic pop +- (void)methodThatAlsoDoesntWarn {} +@end + +void BlockFunc() { + void(^aBlockThatWarns)(struct MyStruct) = ^(struct MyStruct a) {}; // expected-warning {{block argument encoding of size 31 is larger than 10 bytes}} +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-encoding-larger-than=" + void(^aBlockThatDoesntWarn)(struct MyStruct) = ^(struct MyStruct a) {}; +#pragma clang diagnostic pop + void(^aBlockThatAlsoDoesntWarn)() = ^() {}; +}