From: Fariborz Jahanian Date: Fri, 22 Aug 2014 23:17:52 +0000 (+0000) Subject: Objective-C. Warn when @encode'ing provides an incomplete X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=024d9c65e9d3887045c82be09e4f630f19da48b4;p=clang Objective-C. Warn when @encode'ing provides an incomplete type encoding because in certain cases, such as for vector types, because we still haven't designed encoding for them. rdar://9255564 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216301 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index dd5c199f32..6b2a3bac3f 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1379,7 +1379,8 @@ public: /// /// If \p Field is specified then record field names are also encoded. void getObjCEncodingForType(QualType T, std::string &S, - const FieldDecl *Field=nullptr) const; + const FieldDecl *Field=nullptr, + QualType *NotEncodedT=nullptr) const; /// \brief Emit the Objective-C property type encoding for the given /// type \p T into \p S. @@ -2275,12 +2276,14 @@ private: bool StructField = false, bool EncodeBlockParameters = false, bool EncodeClassNames = false, - bool EncodePointerToObjCTypedef = false) const; + bool EncodePointerToObjCTypedef = false, + QualType *NotEncodedT=nullptr) const; // Adds the encoding of the structure's members. void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S, const FieldDecl *Field, - bool includeVBases = true) const; + bool includeVBases = true, + QualType *NotEncodedT=nullptr) const; public: // Adds the encoding of a method parameter or return type. void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3a14e4c4b4..869be0477b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2195,6 +2195,9 @@ def warn_type_attribute_wrong_type : Warning< "'%0' only applies to %select{function|pointer|" "Objective-C object or block pointer}1 types; type here is %2">, InGroup; +def warn_incomplete_encoded_type : Warning< + "encoding of %0 type is incomplete because %1 component has unknown encoding">, + InGroup>; def warn_attribute_requires_functions_or_static_globals : Warning< "%0 only applies to variables with static storage duration and functions">, InGroup; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 92ed6993eb..3a15096815 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5097,13 +5097,15 @@ void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { } void ASTContext::getObjCEncodingForType(QualType T, std::string& S, - const FieldDecl *Field) const { + const FieldDecl *Field, + QualType *NotEncodedT) const { // We follow the behavior of gcc, expanding structures which are // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. getObjCEncodingForTypeImpl(T, S, true, true, Field, - true /* outermost type */); + true /* outermost type */, false, false, + false, false, false, NotEncodedT); } void ASTContext::getObjCEncodingForPropertyType(QualType T, @@ -5229,7 +5231,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool StructField, bool EncodeBlockParameters, bool EncodeClassNames, - bool EncodePointerToObjCTypedef) const { + bool EncodePointerToObjCTypedef, + QualType *NotEncodedT) const { CanQualType CT = getCanonicalType(T); switch (CT->getTypeClass()) { case Type::Builtin: @@ -5245,16 +5248,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Complex: { const ComplexType *CT = T->castAs(); S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr, - false, false); + getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr); return; } case Type::Atomic: { const AtomicType *AT = T->castAs(); S += 'A'; - getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr, - false, false); + getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr); return; } @@ -5325,7 +5326,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getLegacyIntegralTypeEncoding(PointeeTy); getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, - nullptr); + nullptr, false, false, false, false, false, false, + NotEncodedT); return; } @@ -5353,7 +5355,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, FD); + false, ExpandStructures, FD, + false, false, false, false, false, false, + NotEncodedT); S += ']'; } return; @@ -5385,7 +5389,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (ExpandStructures) { S += '='; if (!RDecl->isUnion()) { - getObjCEncodingForStructureImpl(RDecl, S, FD); + getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT); } else { for (const auto *Field : RDecl->fields()) { if (FD) { @@ -5404,7 +5408,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl(qt, S, false, true, FD, /*OutermostType*/false, /*EncodingProperty*/false, - /*StructField*/true); + /*StructField*/true, + false, false, false, NotEncodedT); } } } @@ -5424,7 +5429,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl( FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures, FD, false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames); + false /* StructField */, EncodeBlockParameters, EncodeClassNames, false, + NotEncodedT); // Block self S += "@?"; // Block parameters @@ -5433,7 +5439,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl( I, S, ExpandPointedToStructures, ExpandStructures, FD, false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames); + false /* StructField */, EncodeBlockParameters, EncodeClassNames, + false, NotEncodedT); } S += '>'; } @@ -5475,7 +5482,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, else getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD, false, false, false, false, false, - EncodePointerToObjCTypedef); + EncodePointerToObjCTypedef, + NotEncodedT); } S += '}'; return; @@ -5562,19 +5570,21 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // gcc just blithely ignores member pointers. // FIXME: we shoul do better than that. 'M' is available. case Type::MemberPointer: - return; - + // This matches gcc's encoding, even though technically it is insufficient. + //FIXME. We should do a better job than gcc. case Type::Vector: case Type::ExtVector: - // This matches gcc's encoding, even though technically it is - // insufficient. - // FIXME. We should do a better job than gcc. - return; - + // Until we have a coherent encoding of these three types, issue warning. + { if (NotEncodedT) + *NotEncodedT = T; + return; + } + + // We could see an undeduced auto type here during error recovery. + // Just ignore it. case Type::Auto: - // We could see an undeduced auto type here during error recovery. - // Just ignore it. return; + #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) @@ -5593,7 +5603,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, std::string &S, const FieldDecl *FD, - bool includeVBases) const { + bool includeVBases, + QualType *NotEncodedT) const { assert(RDecl && "Expected non-null RecordDecl"); assert(!RDecl->isUnion() && "Should not be called for unions"); if (!RDecl->getDefinition()) @@ -5697,7 +5708,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, // in the initial structure. Note that this differs from gcc which // expands virtual bases each time one is encountered in the hierarchy, // making the encoding type bigger than it really is. - getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false); + getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false, + NotEncodedT); assert(!base->isEmpty()); #ifndef NDEBUG CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); @@ -5721,7 +5733,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, getObjCEncodingForTypeImpl(qt, S, false, true, FD, /*OutermostType*/false, /*EncodingProperty*/false, - /*StructField*/true); + /*StructField*/true, + false, false, false, NotEncodedT); #ifndef NDEBUG CurOffs += getTypeSize(field->getType()); #endif diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 22c55a7726..7ade45d492 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -995,7 +995,11 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, return ExprError(); std::string Str; - Context.getObjCEncodingForType(EncodedType, Str); + QualType NotEncodedT; + Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT); + if (!NotEncodedT.isNull()) + Diag(AtLoc, diag::warn_incomplete_encoded_type) + << EncodedType << NotEncodedT; // The type of @encode is the same as the type of the corresponding string, // which is an array type. diff --git a/test/SemaObjC/encode-typeof-test.m b/test/SemaObjC/encode-typeof-test.m index 2cda973968..fe8f29c3b9 100644 --- a/test/SemaObjC/encode-typeof-test.m +++ b/test/SemaObjC/encode-typeof-test.m @@ -24,3 +24,22 @@ int main() int i; typeof(@encode(typeof(i))) e = @encode(typeof(Intf)); // expected-warning {{initializer-string for char array is too long}} } + +// rdar://9255564 +typedef short short8 __attribute__((ext_vector_type(8))); + +struct foo { + char a; + int b; + long c; + short8 d; + int array[4]; + short int bitfield1:5; + unsigned short bitfield2:11; + char *string; +}; + +const char *RetEncode () { + return @encode(struct foo); // expected-warning {{encoding of 'struct foo' type is incomplete because 'short8' (vector of 8 'short' values) component has unknown encoding}} +} +