Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -2864,18 +2864,53 @@ private: void InitBuiltinType(CanQualType &R, BuiltinType::Kind K); + class ObjCEncOptions { + unsigned Bits; + + ObjCEncOptions(unsigned Bits) : Bits(Bits) {} + + public: + ObjCEncOptions() : Bits(0) {} + ObjCEncOptions(const ObjCEncOptions &RHS) : Bits(RHS.Bits) {} + +#define OPT_LIST(V) \ + V(ExpandPointedToStructures, 0) \ + V(ExpandStructures, 1) \ + V(IsOutermostType, 2) \ + V(EncodingProperty, 3) \ + V(IsStructField, 4) \ + V(EncodeBlockParameters, 5) \ + V(EncodeClassNames, 6) \ + V(EncodePointerToObjCTypedef, 7) + +#define V(N,I) ObjCEncOptions set##N() { Bits |= 1 << I; return *this; } +OPT_LIST(V) +#undef V + +#define V(N,I) bool N() { return Bits & 1 << I; } +OPT_LIST(V) +#undef V + +#undef OPT_LIST + + LLVM_NODISCARD ObjCEncOptions keepingOnly(ObjCEncOptions Mask) { + return Bits & Mask.Bits; + } + + LLVM_NODISCARD ObjCEncOptions forComponentType() { + ObjCEncOptions Mask = ObjCEncOptions() + .setIsOutermostType() + .setIsStructField() + .setEncodePointerToObjCTypedef(); + return Bits & ~Mask.Bits; + } + }; + // Return the Objective-C type encoding for a given type. void getObjCEncodingForTypeImpl(QualType t, std::string &S, - bool ExpandPointedToStructures, - bool ExpandStructures, + ObjCEncOptions Options, const FieldDecl *Field, - bool OutermostType = false, - bool EncodingProperty = false, - bool StructField = false, - bool EncodeBlockParameters = false, - bool EncodeClassNames = false, - bool EncodePointerToObjCTypedef = false, - QualType *NotEncodedT=nullptr) const; + QualType *NotEncodedT = nullptr) const; // Adds the encoding of the structure's members. void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S, Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -6303,13 +6303,13 @@ // Encode type qualifer, 'in', 'inout', etc. for the parameter. getObjCEncodingForTypeQualifier(QT, S); // Encode parameter type. - getObjCEncodingForTypeImpl(T, S, /*ExpandPointedToStructures=*/true, - /*ExpandStructures=*/true, /*Field=*/nullptr, - /*OutermostType=*/true, - /*EncodingProperty=*/false, - /*StructField=*/false, - /*EncodeBlockParameters=*/Extended, - /*EncodeClassNames=*/Extended); + ObjCEncOptions Options = ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType(); + if (Extended) + Options.setEncodeBlockParameters().setEncodeClassNames(); + getObjCEncodingForTypeImpl(T, S, Options, /*Field=*/nullptr); } /// getObjCEncodingForMethodDecl - Return the encoded type for this method @@ -6501,13 +6501,12 @@ // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. - getObjCEncodingForTypeImpl(T, S, /*ExpandPointedToStructures=*/true, - /*ExpandStructures=*/true, Field, - /*OutermostType=*/true, /*EncodingProperty=*/false, - /*StructField=*/false, - /*EncodeBlockParameters=*/false, - /*EncodeClassNames=*/false, - /*EncodePointerToObjCTypedef=*/false, NotEncodedT); + getObjCEncodingForTypeImpl(T, S, + ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType(), + Field, NotEncodedT); } void ASTContext::getObjCEncodingForPropertyType(QualType T, @@ -6515,9 +6514,13 @@ // Encode result type. // GCC has some special rules regarding encoding of properties which // closely resembles encoding of ivars. - getObjCEncodingForTypeImpl( - T, S, /*ExpandPointedToStructures=*/true, /*ExpandStructures=*/true, - /*Field=*/nullptr, /*OutermostType=*/true, /*EncodingProperty=*/true); + getObjCEncodingForTypeImpl(T, S, + ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType() + .setEncodingProperty(), + /*Field=*/nullptr); } static char getObjCEncodingForPrimitiveKind(const ASTContext *C, @@ -6664,16 +6667,9 @@ } // FIXME: Use SmallString for accumulating string. -void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, - bool ExpandPointedToStructures, - bool ExpandStructures, +void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, + ObjCEncOptions Options, const FieldDecl *FD, - bool OutermostType, - bool EncodingProperty, - bool StructField, - bool EncodeBlockParameters, - bool EncodeClassNames, - bool EncodePointerToObjCTypedef, QualType *NotEncodedT) const { CanQualType CT = getCanonicalType(T); switch (CT->getTypeClass()) { @@ -6690,18 +6686,16 @@ case Type::Complex: { const auto *CT = T->castAs(); S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, - /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/false, /*Field=*/nullptr); + getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(), + /*Field=*/nullptr); return; } case Type::Atomic: { const auto *AT = T->castAs(); S += 'A'; - getObjCEncodingForTypeImpl(AT->getValueType(), S, - /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/false, /*Field=*/nullptr); + getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(), + /*Field=*/nullptr); return; } @@ -6727,11 +6721,11 @@ // the pointer itself gets ignored, _unless_ we are looking at a typedef! // Also, do not emit the 'r' for anything but the outermost type! if (isa(T.getTypePtr())) { - if (OutermostType && T.isConstQualified()) { + if (Options.IsOutermostType() && T.isConstQualified()) { isReadOnly = true; S += 'r'; } - } else if (OutermostType) { + } else if (Options.IsOutermostType()) { QualType P = PointeeTy; while (P->getAs()) P = P->getAs()->getPointeeType(); @@ -6771,13 +6765,11 @@ S += '^'; getLegacyIntegralTypeEncoding(PointeeTy); - getObjCEncodingForTypeImpl( - PointeeTy, S, /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/ExpandPointedToStructures, /*Field=*/nullptr, - /*OutermostType=*/false, /*EncodingProperty=*/false, - /*StructField=*/false, /*EncodeBlockParameters=*/false, - /*EncodeClassNames=*/false, /*EncodePointerToObjCTypedef=*/false, - NotEncodedT); + ObjCEncOptions NewOptions; + if (Options.ExpandPointedToStructures()) + NewOptions.setExpandStructures(); + getObjCEncodingForTypeImpl(PointeeTy, S, NewOptions, + /*Field=*/nullptr, NotEncodedT); return; } @@ -6786,13 +6778,13 @@ case Type::VariableArray: { const auto *AT = cast(CT); - if (isa(AT) && !StructField) { + if (isa(AT) && !Options.IsStructField()) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; - getObjCEncodingForTypeImpl(AT->getElementType(), S, - /*ExpandPointedToStructures=*/false, - ExpandStructures, FD); + getObjCEncodingForTypeImpl( + AT->getElementType(), S, + Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD); } else { S += '['; @@ -6807,11 +6799,8 @@ getObjCEncodingForTypeImpl( AT->getElementType(), S, - /*ExpandPointedToStructures=*/false, ExpandStructures, FD, - /*OutermostType=*/false, - /*EncodingProperty=*/false, /*StructField=*/false, - /*EncodeBlockParameters=*/false, /*EncodeClassNames=*/false, - /*EncodePointerToObjCTypedef=*/false, NotEncodedT); + Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD, + NotEncodedT); S += ']'; } return; @@ -6837,7 +6826,7 @@ } else { S += '?'; } - if (ExpandStructures) { + if (Options.ExpandStructures()) { S += '='; if (!RDecl->isUnion()) { getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT); @@ -6852,18 +6841,15 @@ // Special case bit-fields. if (Field->isBitField()) { getObjCEncodingForTypeImpl(Field->getType(), S, - /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/true, Field); + ObjCEncOptions().setExpandStructures(), + Field); } else { QualType qt = Field->getType(); getLegacyIntegralTypeEncoding(qt); getObjCEncodingForTypeImpl( - qt, S, /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/true, FD, /*OutermostType=*/false, - /*EncodingProperty=*/false, - /*StructField=*/true, /*EncodeBlockParameters=*/false, - /*EncodeClassNames=*/false, - /*EncodePointerToObjCTypedef=*/false, NotEncodedT); + qt, S, + ObjCEncOptions().setExpandStructures().setIsStructField(), FD, + NotEncodedT); } } } @@ -6875,26 +6861,20 @@ case Type::BlockPointer: { const auto *BT = T->castAs(); S += "@?"; // Unlike a pointer-to-function, which is "^?". - if (EncodeBlockParameters) { + if (Options.EncodeBlockParameters()) { const auto *FT = BT->getPointeeType()->castAs(); S += '<'; // Block return type - getObjCEncodingForTypeImpl( - FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures, - FD, /*OutermostType=*/false, EncodingProperty, - /*StructField=*/false, EncodeBlockParameters, EncodeClassNames, - /*EncodePointerToObjCTypedef=*/false, NotEncodedT); + getObjCEncodingForTypeImpl(FT->getReturnType(), S, + Options.forComponentType(), FD, NotEncodedT); // Block self S += "@?"; // Block parameters if (const auto *FPT = dyn_cast(FT)) { for (const auto &I : FPT->param_types()) - getObjCEncodingForTypeImpl( - I, S, ExpandPointedToStructures, ExpandStructures, FD, - /*OutermostType=*/false, EncodingProperty, - /*StructField=*/false, EncodeBlockParameters, EncodeClassNames, - /*EncodePointerToObjCTypedef=*/false, NotEncodedT); + getObjCEncodingForTypeImpl(I, S, Options.forComponentType(), FD, + NotEncodedT); } S += '>'; } @@ -6922,7 +6902,7 @@ ObjCInterfaceDecl *OI = T->castAs()->getInterface(); S += '{'; S += OI->getObjCRuntimeNameAsString(); - if (ExpandStructures) { + if (Options.ExpandStructures()) { S += '='; SmallVector Ivars; DeepCollectObjCIvars(OI, true, Ivars); @@ -6930,17 +6910,15 @@ const FieldDecl *Field = Ivars[i]; if (Field->isBitField()) getObjCEncodingForTypeImpl(Field->getType(), S, - /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/true, Field); - else - getObjCEncodingForTypeImpl( - Field->getType(), S, - /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/true, FD, /*OutermostType=*/false, - /*EncodingProperty=*/false, - /*StructField=*/false, /*EncodeBlockParameters=*/false, - /*EncodeClassNames=*/false, EncodePointerToObjCTypedef, - NotEncodedT); + ObjCEncOptions().setExpandStructures(), + Field); + else { + ObjCEncOptions NewOptions = ObjCEncOptions().setExpandStructures(); + if (Options.EncodePointerToObjCTypedef()) + NewOptions = NewOptions.setEncodePointerToObjCTypedef(); + getObjCEncodingForTypeImpl(Field->getType(), S, NewOptions, FD, + NotEncodedT); + } } } S += '}'; @@ -6963,10 +6941,13 @@ } if (OPT->isObjCQualifiedIdType()) { - getObjCEncodingForTypeImpl(getObjCIdType(), S, - ExpandPointedToStructures, - ExpandStructures, FD); - if (FD || EncodingProperty || EncodeClassNames) { + getObjCEncodingForTypeImpl( + getObjCIdType(), S, + Options.keepingOnly(ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures()), + FD); + if (FD || Options.EncodingProperty() || Options.EncodeClassNames()) { // Note that we do extended encoding of protocol qualifer list // Only when doing ivar or property encoding. S += '"'; @@ -6981,9 +6962,9 @@ } QualType PointeeTy = OPT->getPointeeType(); - if (!EncodingProperty && + if (!Options.EncodingProperty() && isa(PointeeTy.getTypePtr()) && - !EncodePointerToObjCTypedef) { + !Options.EncodePointerToObjCTypedef()) { // Another historical/compatibility reason. // We encode the underlying type which comes out as // {...}; @@ -7002,21 +6983,17 @@ } } } - getObjCEncodingForTypeImpl( - PointeeTy, S, - /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/ExpandPointedToStructures, - /*Field=*/nullptr, - /*OutermostType=*/false, /*EncodingProperty=*/false, - /*StructField=*/false, /*EncodeBlockParameters=*/false, - /*EncodeClassNames=*/false, - /*EncodePointerToObjCTypedef=*/true); + ObjCEncOptions NewOptions = + ObjCEncOptions().setEncodePointerToObjCTypedef(); + if (Options.ExpandPointedToStructures()) + NewOptions.setExpandStructures(); + getObjCEncodingForTypeImpl(PointeeTy, S, NewOptions, /*Field=*/nullptr); return; } S += '@'; if (OPT->getInterfaceDecl() && - (FD || EncodingProperty || EncodeClassNames)) { + (FD || Options.EncodingProperty() || Options.EncodeClassNames())) { S += '"'; S += OPT->getInterfaceDecl()->getObjCRuntimeNameAsString(); for (const auto *I : OPT->quals()) { @@ -7030,7 +7007,7 @@ } // gcc just blithely ignores member pointers. - // FIXME: we shoul do better than that. 'M' is available. + // FIXME: we should do better than that. 'M' is available. case Type::MemberPointer: // This matches gcc's encoding, even though technically it is insufficient. //FIXME. We should do a better job than gcc. @@ -7193,13 +7170,8 @@ QualType qt = field->getType(); getLegacyIntegralTypeEncoding(qt); getObjCEncodingForTypeImpl( - qt, S, /*ExpandPointedToStructures=*/false, - /*ExpandStructures=*/true, FD, - /*OutermostType=*/false, - /*EncodingProperty=*/false, - /*StructField=*/true, /*EncodeBlockParameters=*/false, - /*EncodeClassNames=*/false, /*EncodePointerToObjCTypedef=*/false, - NotEncodedT); + qt, S, ObjCEncOptions().setExpandStructures().setIsStructField(), + FD, NotEncodedT); #ifndef NDEBUG CurOffs += getTypeSize(field->getType()); #endif