diff options
author | John McCall <rjmccall@apple.com> | 2013-04-16 07:28:30 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2013-04-16 07:28:30 +0000 |
commit | 76da55d3a49e1805f51b1ced7c5da5bcd7f759d8 (patch) | |
tree | 9681395543b144659b99a401d3a1ff0260bc08b4 | |
parent | 459ef03126f9f0420efb3355e3b2ed3c1fdfb38a (diff) |
Basic support for Microsoft property declarations and
references thereto.
Patch by Tong Shen!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179585 91177308-0d34-0410-b5e6-96231b3b80d8
50 files changed, 1029 insertions, 34 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 7afb45c23a..5506d211cc 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -2984,6 +2984,56 @@ public: friend class ASTDeclReader; }; +/// An instance of this class represents the declaration of a property +/// member. This is a Microsoft extension to C++, first introduced in +/// Visual Studio .NET 2003 as a parallel to similar features in C# +/// and Managed C++. +/// +/// A property must always be a non-static class member. +/// +/// A property member superficially resembles a non-static data +/// member, except preceded by a property attribute: +/// __declspec(property(get=GetX, put=PutX)) int x; +/// Either (but not both) of the 'get' and 'put' names may be omitted. +/// +/// A reference to a property is always an lvalue. If the lvalue +/// undergoes lvalue-to-rvalue conversion, then a getter name is +/// required, and that member is called with no arguments. +/// If the lvalue is assigned into, then a setter name is required, +/// and that member is called with one argument, the value assigned. +/// Both operations are potentially overloaded. Compound assignments +/// are permitted, as are the increment and decrement operators. +/// +/// The getter and putter methods are permitted to be overloaded, +/// although their return and parameter types are subject to certain +/// restrictions according to the type of the property. +/// +/// A property declared using an incomplete array type may +/// additionally be subscripted, adding extra parameters to the getter +/// and putter methods. +class MSPropertyDecl : public DeclaratorDecl { + IdentifierInfo *GetterId, *SetterId; + +public: + MSPropertyDecl(DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, + SourceLocation StartL, IdentifierInfo *Getter, + IdentifierInfo *Setter): + DeclaratorDecl(MSProperty, DC, L, N, T, TInfo, StartL), GetterId(Getter), + SetterId(Setter) {} + + static MSPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return D->getKind() == MSProperty; } + + bool hasGetter() const { return GetterId != NULL; } + IdentifierInfo* getGetterId() const { return GetterId; } + bool hasSetter() const { return SetterId != NULL; } + IdentifierInfo* getSetterId() const { return SetterId; } + + friend class ASTDeclReader; +}; + /// Insertion operator for diagnostics. This allows sending an AccessSpecifier /// into a diagnostic with <<. const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 04f6fb64cf..3189426f9d 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -29,6 +29,7 @@ class CXXConstructorDecl; class CXXDestructorDecl; class CXXMethodDecl; class CXXTemporary; +class MSPropertyDecl; class TemplateArgumentListInfo; class UuidAttr; @@ -560,6 +561,64 @@ public: } }; +/// A member reference to an MSPropertyDecl. This expression always +/// has pseudo-object type, and therefore it is typically not +/// encountered in a fully-typechecked expression except within the +/// syntactic form of a PseudoObjectExpr. +class MSPropertyRefExpr : public Expr { + Expr *BaseExpr; + MSPropertyDecl *TheDecl; + SourceLocation MemberLoc; + bool IsArrow; + NestedNameSpecifierLoc QualifierLoc; + +public: + MSPropertyRefExpr(Expr *baseExpr, MSPropertyDecl *decl, bool isArrow, + QualType ty, ExprValueKind VK, + NestedNameSpecifierLoc qualifierLoc, + SourceLocation nameLoc) + : Expr(MSPropertyRefExprClass, ty, VK, OK_Ordinary, + /*type-dependent*/ false, baseExpr->isValueDependent(), + baseExpr->isInstantiationDependent(), + baseExpr->containsUnexpandedParameterPack()), + BaseExpr(baseExpr), TheDecl(decl), + MemberLoc(nameLoc), IsArrow(isArrow), + QualifierLoc(qualifierLoc) {} + + MSPropertyRefExpr(EmptyShell Empty) : Expr(MSPropertyRefExprClass, Empty) {} + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocStart(), getLocEnd()); + } + bool isImplicitAccess() const { + return getBaseExpr() && getBaseExpr()->isImplicitCXXThis(); + } + SourceLocation getLocStart() const { + if (!isImplicitAccess()) + return BaseExpr->getLocStart(); + else if (QualifierLoc) + return QualifierLoc.getBeginLoc(); + else + return MemberLoc; + } + SourceLocation getLocEnd() const { return getMemberLoc(); } + + child_range children() { + return child_range((Stmt**)&BaseExpr, (Stmt**)&BaseExpr + 1); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSPropertyRefExprClass; + } + + Expr *getBaseExpr() const { return BaseExpr; } + MSPropertyDecl *getPropertyDecl() const { return TheDecl; } + bool isArrow() const { return IsArrow; } + SourceLocation getMemberLoc() const { return MemberLoc; } + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + friend class ASTStmtReader; +}; + /// CXXUuidofExpr - A microsoft C++ @c __uuidof expression, which gets /// the _GUID that corresponds to the supplied type or expression. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 0191964bbf..33534ecc7c 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1671,6 +1671,10 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) { return true; } +DEF_TRAVERSE_DECL(MSPropertyDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + }) + DEF_TRAVERSE_DECL(FieldDecl, { TRY_TO(TraverseDeclaratorHelper(D)); if (D->isBitField()) @@ -2058,6 +2062,10 @@ DEF_TRAVERSE_STMT(CXXTypeidExpr, { TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); }) +DEF_TRAVERSE_STMT(MSPropertyRefExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); +}) + DEF_TRAVERSE_STMT(CXXUuidofExpr, { // The child-iterator will pick up the arg if it's an expression, // but not if it's a type. diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 37aa332b81..441a79a23b 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -928,6 +928,10 @@ def TypeTagForDatatype : InheritableAttr { // Microsoft-related attributes +def MsProperty : Attr { + let Spellings = [Declspec<"property">]; +} + def MsStruct : InheritableAttr { let Spellings = [Declspec<"ms_struct">]; } diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index 45742bc665..ebcd81252f 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -34,14 +34,15 @@ def Named : Decl<1>; def UnresolvedUsingValue : DDecl<Value>; def IndirectField : DDecl<Value>; def Declarator : DDecl<Value, 1>; + def Field : DDecl<Declarator>; + def ObjCIvar : DDecl<Field>; + def ObjCAtDefsField : DDecl<Field>; + def MSProperty : DDecl<Declarator>; def Function : DDecl<Declarator>, DeclContext; def CXXMethod : DDecl<Function>; def CXXConstructor : DDecl<CXXMethod>; def CXXDestructor : DDecl<CXXMethod>; def CXXConversion : DDecl<CXXMethod>; - def Field : DDecl<Declarator>; - def ObjCIvar : DDecl<Field>; - def ObjCAtDefsField : DDecl<Field>; def Var : DDecl<Declarator>; def ImplicitParam : DDecl<Var>; def ParmVar : DDecl<Var>; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 04a433c0a6..788b1cf317 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -527,6 +527,22 @@ def err_ms_declspec_type : Error< "__declspec attributes must be an identifier or string literal">; def warn_ms_declspec_unknown : Warning< "unknown __declspec attribute %0 ignored">, InGroup<UnknownAttributes>; +def err_ms_property_no_getter_or_putter : Error< + "property does not specify a getter or a putter">; +def err_ms_property_unknown_accessor : Error< + "expected 'get' or 'put' in property declaration">; +def err_ms_property_has_set_accessor : Error< + "putter for property must be specified as 'put', not 'set'">; +def err_ms_property_missing_accessor_kind : Error< + "missing 'get=' or 'put='">; +def err_ms_property_expected_equal : Error< + "expected '=' after '%0'">; +def err_ms_property_duplicate_accessor : Error< + "property declaration specifies '%0' accessor twice">; +def err_ms_property_expected_accessor_name : Error< + "expected name of accessor method">; +def err_ms_property_expected_comma_or_rparen : Error< + "expected ',' or ')' at end of property accessor list">; /// C++ Templates def err_expected_template : Error<"expected template">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 17a7f00b63..cfb1798def 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1810,6 +1810,19 @@ def err_attribute_section_local_variable : Error< def warn_mismatched_section : Warning< "section does not match previous declaration">, InGroup<Section>; +def err_anonymous_property: Error< + "anonymous property is not supported">; +def err_property_is_variably_modified: Error< + "property '%0' has a variably modified type">; +def err_no_getter_for_property : Error< + "no getter defined for property '%0'">; +def err_no_setter_for_property : Error< + "no setter defined for property '%0'">; +def error_cannot_find_suitable_getter : Error< + "cannot find suitable getter for property '%0'">; +def error_cannot_find_suitable_setter : Error< + "cannot find suitable setter for property '%0'">; + def err_attribute_aligned_not_power_of_two : Error< "requested alignment is not a power of 2">; def err_attribute_aligned_greater_than_8192 : Error< diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 8f6a1c9f98..979555e1a6 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -163,6 +163,7 @@ def BlockExpr : DStmt<Expr>; def OpaqueValueExpr : DStmt<Expr>; // Microsoft Extensions. +def MSPropertyRefExpr : DStmt<Expr>; def CXXUuidofExpr : DStmt<Expr>; def SEHTryStmt : Stmt; def SEHExceptStmt : Stmt; diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 0f0d2185b0..d5f31779a6 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -96,6 +96,10 @@ private: /// type_tag_for_datatype attribute. unsigned IsTypeTagForDatatype : 1; + /// True if this has extra information associated with a + /// Microsoft __delcspec(property) attribute. + unsigned IsProperty : 1; + unsigned AttrKind : 8; /// \brief The location of the 'unavailable' keyword in an @@ -134,6 +138,11 @@ public: unsigned LayoutCompatible : 1; unsigned MustBeNull : 1; }; + struct PropertyData { + IdentifierInfo *GetterId, *SetterId; + PropertyData(IdentifierInfo *getterId, IdentifierInfo *setterId) + : GetterId(getterId), SetterId(setterId) {} + }; private: TypeTagForDatatypeData &getTypeTagForDatatypeDataSlot() { @@ -152,6 +161,16 @@ private: return *reinterpret_cast<const ParsedType *>(this + 1); } + PropertyData &getPropertyDataBuffer() { + assert(IsProperty); + return *reinterpret_cast<PropertyData*>(this + 1); + } + + const PropertyData &getPropertyDataBuffer() const { + assert(IsProperty); + return *reinterpret_cast<const PropertyData*>(this + 1); + } + AttributeList(const AttributeList &) LLVM_DELETED_FUNCTION; void operator=(const AttributeList &) LLVM_DELETED_FUNCTION; void operator delete(void *) LLVM_DELETED_FUNCTION; @@ -169,7 +188,8 @@ private: AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), - IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) { + IsTypeTagForDatatype(false), IsProperty(false), NextInPosition(0), + NextInPool(0) { if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*)); AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } @@ -188,7 +208,7 @@ private: AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), - IsTypeTagForDatatype(false), + IsTypeTagForDatatype(false), IsProperty(false), UnavailableLoc(unavailable), MessageExpr(messageExpr), NextInPosition(0), NextInPool(0) { new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); @@ -208,7 +228,8 @@ private: AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), - IsTypeTagForDatatype(true), NextInPosition(NULL), NextInPool(NULL) { + IsTypeTagForDatatype(true), IsProperty(false), NextInPosition(NULL), + NextInPool(NULL) { TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot(); new (&ExtraData.MatchingCType) ParsedType(matchingCType); ExtraData.LayoutCompatible = layoutCompatible; @@ -225,11 +246,28 @@ private: AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), - IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) { + IsTypeTagForDatatype(false), IsProperty(false), NextInPosition(0), + NextInPool(0) { new (&getTypeBuffer()) ParsedType(typeArg); AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } + /// Constructor for microsoft __declspec(property) attribute. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), + AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), + SyntaxUsed(syntaxUsed), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(true), NextInPosition(0), + NextInPool(0) { + new (&getPropertyDataBuffer()) PropertyData(getterId, setterId); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + friend class AttributePool; friend class AttributeFactory; @@ -253,6 +291,11 @@ public: IdentifierInfo *getParameterName() const { return ParmName; } SourceLocation getParameterLoc() const { return ParmLoc; } + /// Is this the Microsoft __declspec(property) attribute? + bool isDeclspecPropertyAttribute() const { + return IsProperty; + } + bool isAlignasAttribute() const { // FIXME: Use a better mechanism to determine this. return getKind() == AT_Aligned && SyntaxUsed == AS_Keyword; @@ -379,6 +422,11 @@ public: return getTypeBuffer(); } + const PropertyData &getPropertyData() const { + assert(isDeclspecPropertyAttribute() && "Not a __delcspec(property) attribute"); + return getPropertyDataBuffer(); + } + /// \brief Get an index into the attribute spelling list /// defined in Attr.td. This index is used by an attribute /// to pretty print itself. @@ -402,6 +450,10 @@ public: TypeTagForDatatypeAllocSize = sizeof(AttributeList) + (sizeof(AttributeList::TypeTagForDatatypeData) + sizeof(void *) - 1) + / sizeof(void*) * sizeof(void*), + PropertyAllocSize = + sizeof(AttributeList) + + (sizeof(AttributeList::PropertyData) + sizeof(void *) - 1) / sizeof(void*) * sizeof(void*) }; @@ -548,6 +600,20 @@ public: parmName, parmLoc, typeArg, syntaxUsed)); } + + AttributeList *createPropertyAttribute( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + AttributeList::Syntax syntaxUsed) { + void *memory = allocate(AttributeFactory::PropertyAllocSize); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + parmName, parmLoc, + getterId, setterId, + syntaxUsed)); + } }; /// addAttributeLists - Add two AttributeLists together @@ -703,6 +769,21 @@ public: return attr; } + /// Add microsoft __delspec(property) attribute. + AttributeList * + addNewPropertyAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + IdentifierInfo *getterId, IdentifierInfo *setterId, + AttributeList::Syntax syntaxUsed) { + AttributeList *attr = + pool.createPropertyAttribute(attrName, attrRange, scopeName, scopeLoc, + parmName, parmLoc, getterId, setterId, + syntaxUsed); + add(attr); + return attr; + } + AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name, SourceLocation loc, int arg) { AttributeList *attr = diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 67dacfc8c7..01e646ef4d 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1586,6 +1586,12 @@ public: Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS); + MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, + SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS, + AttributeList *MSPropertyAttr); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index 8ee8f35ccb..4edfa0a45d 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -401,6 +401,7 @@ namespace clang { Decl *VisitVarDecl(VarDecl *D); Decl *VisitAccessSpecDecl(AccessSpecDecl *D); Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitMSPropertyDecl(MSPropertyDecl *D); Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 9b685ba118..e3f9e0643a 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -951,6 +951,8 @@ namespace clang { DECL_OBJC_PROPERTY_IMPL, /// \brief A FieldDecl record. DECL_FIELD, + /// \brief A MSPropertyDecl record. + DECL_MS_PROPERTY, /// \brief A VarDecl record. DECL_VAR, /// \brief An ImplicitParamDecl record. @@ -1300,6 +1302,7 @@ namespace clang { EXPR_ASTYPE, // AsTypeExpr // Microsoft + EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). STMT_SEH_EXCEPT, // SEHExceptStmt diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9505d299ab..36044826e8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1293,7 +1293,7 @@ bool NamedDecl::isCXXInstanceMember() const { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<MSPropertyDecl>(D)) return true; if (isa<CXXMethodDecl>(D)) return cast<CXXMethodDecl>(D)->isInstance(); @@ -3226,6 +3226,14 @@ BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (Mem) BlockDecl(0, SourceLocation()); } +MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(MSPropertyDecl)); + return new (Mem) MSPropertyDecl(0, SourceLocation(), DeclarationName(), + QualType(), 0, SourceLocation(), + 0, 0); +} + EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, SourceLocation L, IdentifierInfo *Id, QualType T, diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index bd6d99cd59..3f23f3d855 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -493,6 +493,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { c |