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

llvm-svn: 216301
This commit is contained in:
Fariborz Jahanian 2014-08-22 23:17:52 +00:00
parent e82d89cc37
commit 4bf437ecd8
5 changed files with 72 additions and 30 deletions

View File

@ -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,

View File

@ -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<IgnoredAttributes>;
def warn_incomplete_encoded_type : Warning<
"encoding of %0 type is incomplete because %1 component has unknown encoding">,
InGroup<DiagGroup<"encode-type">>;
def warn_attribute_requires_functions_or_static_globals : Warning<
"%0 only applies to variables with static storage duration and functions">,
InGroup<IgnoredAttributes>;

View File

@ -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<ComplexType>();
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<AtomicType>();
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

View File

@ -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.

View File

@ -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}}
}