From 76da55d3a49e1805f51b1ced7c5da5bcd7f759d8 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 16 Apr 2013 07:28:30 +0000 Subject: [PATCH] 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 --- include/clang/AST/DeclCXX.h | 50 ++++++++ include/clang/AST/ExprCXX.h | 59 ++++++++++ include/clang/AST/RecursiveASTVisitor.h | 8 ++ include/clang/Basic/Attr.td | 4 + include/clang/Basic/DeclNodes.td | 7 +- include/clang/Basic/DiagnosticParseKinds.td | 16 +++ include/clang/Basic/DiagnosticSemaKinds.td | 13 ++ include/clang/Basic/StmtNodes.td | 1 + include/clang/Sema/AttributeList.h | 89 +++++++++++++- include/clang/Sema/Sema.h | 6 + include/clang/Sema/Template.h | 1 + include/clang/Serialization/ASTBitCodes.h | 3 + lib/AST/Decl.cpp | 10 +- lib/AST/DeclBase.cpp | 1 + lib/AST/Expr.cpp | 1 + lib/AST/ExprClassification.cpp | 1 + lib/AST/ExprConstant.cpp | 1 + lib/AST/ItaniumMangle.cpp | 1 + lib/AST/StmtPrinter.cpp | 12 ++ lib/AST/StmtProfile.cpp | 5 + lib/CodeGen/CGDecl.cpp | 1 + lib/Parse/ParseDecl.cpp | 122 +++++++++++++++++-- lib/Sema/AttributeList.cpp | 2 + lib/Sema/SemaDeclAttr.cpp | 1 + lib/Sema/SemaDeclCXX.cpp | 110 ++++++++++++++++- lib/Sema/SemaExceptionSpec.cpp | 3 + lib/Sema/SemaExpr.cpp | 69 +++++++++++ lib/Sema/SemaExprCXX.cpp | 5 + lib/Sema/SemaExprMember.cpp | 20 +++- lib/Sema/SemaInit.cpp | 27 +++-- lib/Sema/SemaPseudoObject.cpp | 116 ++++++++++++++++++ lib/Sema/SemaTemplateInstantiateDecl.cpp | 47 ++++++++ lib/Sema/TreeTransform.h | 26 ++++ lib/Serialization/ASTCommon.cpp | 1 + lib/Serialization/ASTReaderDecl.cpp | 10 ++ lib/Serialization/ASTReaderStmt.cpp | 12 ++ lib/Serialization/ASTWriter.cpp | 1 + lib/Serialization/ASTWriterDecl.cpp | 8 ++ lib/Serialization/ASTWriterStmt.cpp | 10 ++ lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + test/Parser/MicrosoftExtensions.cpp | 29 +++++ test/SemaCXX/MicrosoftExtensions.cpp | 124 ++++++++++++++++++++ test/SemaObjC/property-user-setter.m | 2 +- tools/libclang/CIndex.cpp | 1 + tools/libclang/CXCursor.cpp | 1 + tools/libclang/IndexBody.cpp | 6 + tools/libclang/IndexDecl.cpp | 5 + tools/libclang/IndexingContext.cpp | 6 + tools/libclang/IndexingContext.h | 3 + tools/libclang/RecursiveASTVisitor.h | 5 + 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::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; def IndirectField : DDecl; def Declarator : DDecl; + def Field : DDecl; + def ObjCIvar : DDecl; + def ObjCAtDefsField : DDecl; + def MSProperty : DDecl; def Function : DDecl, DeclContext; def CXXMethod : DDecl; def CXXConstructor : DDecl; def CXXDestructor : DDecl; def CXXConversion : DDecl; - def Field : DDecl; - def ObjCIvar : DDecl; - def ObjCAtDefsField : DDecl; def Var : DDecl; def ImplicitParam : DDecl; def ParmVar : DDecl; 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; +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
; +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; def OpaqueValueExpr : DStmt; // Microsoft Extensions. +def MSPropertyRefExpr : DStmt; def CXXUuidofExpr : DStmt; 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(this + 1); } + PropertyData &getPropertyDataBuffer() { + assert(IsProperty); + return *reinterpret_cast(this + 1); + } + + const PropertyData &getPropertyDataBuffer() const { + assert(IsProperty); + return *reinterpret_cast(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(D)) D = cast(D)->getTargetDecl(); - if (isa(D) || isa(D)) + if (isa(D) || isa(D) || isa(D)) return true; if (isa(D)) return cast(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) { case NonTypeTemplateParm: case ObjCMethod: case ObjCProperty: + case MSProperty: return IDNS_Ordinary; case Label: return IDNS_Label; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index b97f4d1d3a..748d3084fe 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2789,6 +2789,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { return false; case CallExprClass: + case MSPropertyRefExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 61bc3e2de5..c2a35f42c1 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: case Expr::FunctionParmPackExprClass: + case Expr::MSPropertyRefExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index d499228af3..3675b2ff44 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -6488,6 +6488,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: + case Expr::MSPropertyRefExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 0f4881e24e..0edad3e017 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2394,6 +2394,7 @@ recurse: case Expr::ImplicitValueInitExprClass: case Expr::ParenListExprClass: case Expr::LambdaExprClass: + case Expr::MSPropertyRefExprClass: llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 7df7fdb92b..a86159f49d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1238,6 +1238,18 @@ void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { OS << ")"; } +void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) { + PrintExpr(Node->getBaseExpr()); + if (Node->isArrow()) + OS << "->"; + else + OS << "."; + if (NestedNameSpecifier *Qualifier = + Node->getQualifierLoc().getNestedNameSpecifier()) + Qualifier->print(OS, Policy); + OS << Node->getPropertyDecl()->getDeclName(); +} + void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { switch (Node->getLiteralOperatorKind()) { case UserDefinedLiteral::LOK_Raw: diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index bfd3132506..5525018f79 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -766,6 +766,11 @@ void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { VisitType(S->getTypeOperand()); } +void StmtProfiler::VisitMSPropertyRefExpr(const MSPropertyRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getPropertyDecl()); +} + void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); ID.AddBoolean(S->isImplicit()); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 8865399b70..15bb6a6e45 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -45,6 +45,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::CXXDestructor: case Decl::CXXConversion: case Decl::Field: + case Decl::MSProperty: case Decl::IndirectField: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 55e2b38271..0094e13d4c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -394,17 +394,119 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, // The property declspec is more complex in that it can take one or two // assignment expressions as a parameter, but the lhs of the assignment // must be named get or put. - // - // For right now, we will just skip to the closing right paren of the - // property expression. - // - // FIXME: we should deal with __declspec(property) at some point because it - // is used in the platform SDK headers for the Parallel Patterns Library - // and ATL. - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - Ident->getNameStart(), tok::r_paren)) + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_expected_lparen_after) + << Ident->getNameStart(); return; + } + BalancedDelimiterTracker T(*this, tok::l_paren); + T.expectAndConsume(diag::err_expected_lparen_after, + Ident->getNameStart(), tok::r_paren); + + enum AccessorKind { + AK_Invalid = -1, + AK_Put = 0, AK_Get = 1 // indices into AccessorNames + }; + IdentifierInfo *AccessorNames[] = { 0, 0 }; + bool HasInvalidAccessor = false; + + // Parse the accessor specifications. + while (true) { + // Stop if this doesn't look like an accessor spec. + if (!Tok.is(tok::identifier)) { + // If the user wrote a completely empty list, use a special diagnostic. + if (Tok.is(tok::r_paren) && !HasInvalidAccessor && + AccessorNames[AK_Put] == 0 && AccessorNames[AK_Get] == 0) { + Diag(Loc, diag::err_ms_property_no_getter_or_putter); + break; + } + + Diag(Tok.getLocation(), diag::err_ms_property_unknown_accessor); + break; + } + + AccessorKind Kind; + SourceLocation KindLoc = Tok.getLocation(); + StringRef KindStr = Tok.getIdentifierInfo()->getName(); + if (KindStr == "get") { + Kind = AK_Get; + } else if (KindStr == "put") { + Kind = AK_Put; + + // Recover from the common mistake of using 'set' instead of 'put'. + } else if (KindStr == "set") { + Diag(KindLoc, diag::err_ms_property_has_set_accessor) + << FixItHint::CreateReplacement(KindLoc, "put"); + Kind = AK_Put; + + // Handle the mistake of forgetting the accessor kind by skipping + // this accessor. + } else if (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)) { + Diag(KindLoc, diag::err_ms_property_missing_accessor_kind); + ConsumeToken(); + HasInvalidAccessor = true; + goto next_property_accessor; + + // Otherwise, complain about the unknown accessor kind. + } else { + Diag(KindLoc, diag::err_ms_property_unknown_accessor); + HasInvalidAccessor = true; + Kind = AK_Invalid; + + // Try to keep parsing unless it doesn't look like an accessor spec. + if (!NextToken().is(tok::equal)) break; + } + + // Consume the identifier. + ConsumeToken(); + + // Consume the '='. + if (Tok.is(tok::equal)) { + ConsumeToken(); + } else { + Diag(Tok.getLocation(), diag::err_ms_property_expected_equal) + << KindStr; + break; + } + + // Expect the method name. + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_ms_property_expected_accessor_name); + break; + } + + if (Kind == AK_Invalid) { + // Just drop invalid accessors. + } else if (AccessorNames[Kind] != NULL) { + // Complain about the repeated accessor, ignore it, and keep parsing. + Diag(KindLoc, diag::err_ms_property_duplicate_accessor) << KindStr; + } else { + AccessorNames[Kind] = Tok.getIdentifierInfo(); + } + ConsumeToken(); + + next_property_accessor: + // Keep processing accessors until we run out. + if (Tok.is(tok::comma)) { + ConsumeAnyToken(); + continue; + + // If we run into the ')', stop without consuming it. + } else if (Tok.is(tok::r_paren)) { + break; + } else { + Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen); + break; + } + } + + // Only add the property attribute if it was well-formed. + if (!HasInvalidAccessor) { + Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0, + SourceLocation(), + AccessorNames[AK_Get], AccessorNames[AK_Put], + AttributeList::AS_Declspec); + } T.skipToEnd(); } else { // We don't recognize this as a valid declspec, but instead of creating the diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index e227d4e840..9ac4c63e19 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -23,6 +23,8 @@ size_t AttributeList::allocated_size() const { if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; else if (IsTypeTagForDatatype) return AttributeFactory::TypeTagForDatatypeAllocSize; + else if (IsProperty) + return AttributeFactory::PropertyAllocSize; return (sizeof(AttributeList) + NumArgs * sizeof(Expr*)); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 1fc1a7cc48..44d0dde0db 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -4889,6 +4889,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, break; // Microsoft attributes: + case AttributeList::AT_MsProperty: break; case AttributeList::AT_MsStruct: handleMsStructAttr(S, D, Attr); break; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8e8ea01395..a318f64765 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1603,6 +1603,13 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } +static AttributeList *getMSPropertyAttr(AttributeList *list) { + for (AttributeList* it = list; it != 0; it = it->getNext()) + if (it->isDeclspecPropertyAttribute()) + return it; + return 0; +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if @@ -1782,8 +1789,16 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, SS.clear(); } - Member = HandleField(S, cast(CurContext), Loc, D, BitWidth, - InitStyle, AS); + AttributeList *MSPropertyAttr = + getMSPropertyAttr(D.getDeclSpec().getAttributes().getList()); + if (MSPropertyAttr) { + Member = HandleMSProperty(S, cast(CurContext), Loc, D, + BitWidth, InitStyle, AS, MSPropertyAttr); + isInstField = false; + } else { + Member = HandleField(S, cast(CurContext), Loc, D, + BitWidth, InitStyle, AS); + } assert(Member && "HandleField never returns null"); } else { assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static); @@ -12096,3 +12111,94 @@ bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, return false; } + +/// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class. +/// +MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, + SourceLocation DeclStart, + Declarator &D, Expr *BitWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS, + AttributeList *MSPropertyAttr) { + IdentifierInfo *II = D.getIdentifier(); + if (!II) { + Diag(DeclStart, diag::err_anonymous_property); + return NULL; + } + SourceLocation Loc = D.getIdentifierLoc(); + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType T = TInfo->getType(); + if (getLangOpts().CPlusPlus) { + CheckExtraCXXDefaultArguments(D); + + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DataMemberType)) { + D.setInvalidType(); + T = Context.IntTy; + TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + } + } + + DiagnoseFunctionSpecifiers(D.getDeclSpec()); + + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); + + // Check to see if this name was declared as a member previously + NamedDecl *PrevDecl = 0; + LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupName(Previous, S); + switch (Previous.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundUnresolvedValue: + PrevDecl = Previous.getAsSingle(); + break; + + case LookupResult::FoundOverloaded: + PrevDecl = Previous.getRepresentativeDecl(); + break; + + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + break; + } + + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) + PrevDecl = 0; + + SourceLocation TSSL = D.getLocStart(); + MSPropertyDecl *NewPD; + const AttributeList::PropertyData &Data = MSPropertyAttr->getPropertyData(); + NewPD = new (Context) MSPropertyDecl(Record, Loc, + II, T, TInfo, TSSL, + Data.GetterId, Data.SetterId); + ProcessDeclAttributes(TUScope, NewPD, D); + NewPD->setAccess(AS); + + if (NewPD->isInvalidDecl()) + Record->setInvalidDecl(); + + if (D.getDeclSpec().isModulePrivateSpecified()) + NewPD->setModulePrivate(); + + if (NewPD->isInvalidDecl() && PrevDecl) { + // Don't introduce NewFD into scope; there's already something + // with the same name in the same scope. + } else if (II) { + PushOnScopeChains(NewPD, S); + } else + Record->addDecl(NewPD); + + return NewPD; +} diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 26c3d354c7..4758718006 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1111,6 +1111,9 @@ CanThrowResult Sema::canThrow(const Expr *E) { // These expressions can never throw. return CT_Cannot; + case Expr::MSPropertyRefExprClass: + llvm_unreachable("Invalid class for expression"); + #define STMT(CLASS, PARENT) case Expr::CLASS##Class: #define STMT_RANGE(Base, First, Last) #define LAST_STMT_RANGE(BASE, FIRST, LAST) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index cafc42daa8..8ddc87af53 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2636,6 +2636,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; } + case Decl::MSProperty: + valueKind = VK_LValue; + break; + case Decl::CXXMethod: // If we're referring to a method with an __unknown_anytype // result type, make the entire expression __unknown_anytype. @@ -4023,6 +4027,63 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, /// to have a function type. static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); +/// Is the given type a placeholder that we need to lower out +/// immediately during argument processing? +static bool isPlaceholderToRemoveAsArg(QualType type) { + // Placeholders are never sugared. + const BuiltinType *placeholder = dyn_cast(type); + if (!placeholder) return false; + + switch (placeholder->getKind()) { + // Ignore all the non-placeholder types. +#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) +#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: +#include "clang/AST/BuiltinTypes.def" + return false; + + // We cannot lower out overload sets; they might validly be resolved + // by the call machinery. + case BuiltinType::Overload: + return false; + + // Unbridged casts in ARC can be handled in some call positions and + // should be left in place. + case BuiltinType::ARCUnbridgedCast: + return false; + + // Pseudo-objects should be converted as soon as possible. + case BuiltinType::PseudoObject: + return true; + + // The debugger mode could theoretically but currently does not try + // to resolve unknown-typed arguments based on known parameter types. + case BuiltinType::UnknownAny: + return true; + + // These are always invalid as call arguments and should be reported. + case BuiltinType::BoundMember: + case BuiltinType::BuiltinFn: + return true; + } + llvm_unreachable("bad builtin type kind"); +} + +/// Check an argument list for placeholders that we won't try to +/// handle later. +static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { + // Apply this processing to all the arguments at once instead of + // dying at the first failure. + bool hasInvalid = false; + for (size_t i = 0, e = args.size(); i != e; i++) { + if (isPlaceholderToRemoveAsArg(args[i]->getType())) { + ExprResult result = S.CheckPlaceholderExpr(args[i]); + if (result.isInvalid()) hasInvalid = true; + else args[i] = result.take(); + } + } + return hasInvalid; +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -4035,6 +4096,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (Result.isInvalid()) return ExprError(); Fn = Result.take(); + if (checkArgsForPlaceholders(*this, ArgExprs)) + return ExprError(); + if (getLangOpts().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. if (isa(Fn)) { @@ -4050,6 +4114,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, Context.VoidTy, VK_RValue, RParenLoc)); } + if (Fn->getType() == Context.PseudoObjectTy) { + ExprResult result = CheckPlaceholderExpr(Fn); + if (result.isInvalid()) return ExprError(); + Fn = result.take(); + } // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3f2cb02673..cfc00502c4 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1170,6 +1170,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, QualType ResultType = Context.getPointerType(AllocType); + if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(ArraySize); + if (result.isInvalid()) return ExprError(); + ArraySize = result.take(); + } // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have // integral or enumeration type with a non-negative value." // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 847db24632..c3642f56ce 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -105,7 +105,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, NamedDecl *D = *I; if (D->isCXXInstanceMember()) { - if (dyn_cast(D) || dyn_cast(D)) + if (dyn_cast(D) || dyn_cast(D) + || dyn_cast(D)) isField = true; CXXRecordDecl *R = cast(D->getDeclContext()); @@ -778,6 +779,19 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, return Owned(result); } +static ExprResult +BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, + MSPropertyDecl *PD, + const DeclarationNameInfo &NameInfo) { + // Property names are always simple identifiers and therefore never + // require any interesting additional storage. + return new (S.Context) MSPropertyRefExpr(BaseExpr, PD, IsArrow, + S.Context.PseudoObjectTy, VK_LValue, + SS.getWithLocInContext(S.Context), + NameInfo.getLoc()); +} + /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow, @@ -935,6 +949,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, SS, FD, FoundDecl, MemberNameInfo); + if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) + return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, + MemberNameInfo); + if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index cd59a328f0..5a5fd26835 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -4136,6 +4136,21 @@ InitializationSequence::InitializationSequence(Sema &S, : FailedCandidateSet(Kind.getLocation()) { ASTContext &Context = S.Context; + // Eliminate non-overload placeholder types in the arguments. We + // need to do this before checking whether types are dependent + // because lowering a pseudo-object expression might well give us + // something of dependent type. + for (unsigned I = 0; I != NumArgs; ++I) + if (Args[I]->getType()->isNonOverloadPlaceholderType()) { + // FIXME: should we be doing this here? + ExprResult result = S.CheckPlaceholderExpr(Args[I]); + if (result.isInvalid()) { + SetFailed(FK_PlaceholderType); + return; + } + Args[I] = result.take(); + } + // C++0x [dcl.init]p16: // The semantics of initializers are as follows. The destination type is // the type of the object or reference being initialized and the source @@ -4153,18 +4168,6 @@ InitializationSequence::InitializationSequence(Sema &S, // Almost everything is a normal sequence. setSequenceKind(NormalSequence); - for (unsigned I = 0; I != NumArgs; ++I) - if (Args[I]->getType()->isNonOverloadPlaceholderType()) { - // FIXME: should we be doing this here? - ExprResult result = S.CheckPlaceholderExpr(Args[I]); - if (result.isInvalid()) { - SetFailed(FK_PlaceholderType); - return; - } - Args[I] = result.take(); - } - - QualType SourceType; Expr *Initializer = 0; if (NumArgs == 1) { diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index b135507b1a..560efa5a4e 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -153,6 +153,23 @@ namespace { refExpr->getRBracket()); } }; + + struct MSPropertyRefRebuilder : Rebuilder { + Expr *NewBase; + MSPropertyRefRebuilder(Sema &S, Expr *newBase) + : Rebuilder(S), NewBase(newBase) {} + + typedef MSPropertyRefExpr specific_type; + Expr *rebuildSpecific(MSPropertyRefExpr *refExpr) { + assert(refExpr->getBaseExpr()); + + return new (S.Context) + MSPropertyRefExpr(NewBase, refExpr->getPropertyDecl(), + refExpr->isArrow(), refExpr->getType(), + refExpr->getValueKind(), refExpr->getQualifierLoc(), + refExpr->getMemberLoc()); + } + }; class PseudoOpBuilder { public: @@ -284,6 +301,18 @@ namespace { ExprResult buildSet(Expr *op, SourceLocation, bool); }; + class MSPropertyOpBuilder : public PseudoOpBuilder { + MSPropertyRefExpr *RefExpr; + + public: + MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : + PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), + RefExpr(refExpr) {} + + Expr *rebuildAndCaptureObject(Expr *); + ExprResult buildGet(); + ExprResult buildSet(Expr *op, SourceLocation, bool); + }; } /// Capture the given expression in an OpaqueValueExpr. @@ -1323,6 +1352,77 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, return msg; } +//===----------------------------------------------------------------------===// +// MSVC __declspec(property) references +//===----------------------------------------------------------------------===// + +Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { + Expr *NewBase = capture(RefExpr->getBaseExpr()); + + syntacticBase = + MSPropertyRefRebuilder(S, NewBase).rebuild(syntacticBase); + + return syntacticBase; +} + +ExprResult MSPropertyOpBuilder::buildGet() { + if (!RefExpr->getPropertyDecl()->hasGetter()) { + S.Diag(RefExpr->getMemberLoc(), diag::err_no_getter_for_property) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + UnqualifiedId GetterName; + IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); + GetterName.setIdentifier(II, RefExpr->getMemberLoc()); + CXXScopeSpec SS; + SS.Adopt(RefExpr->getQualifierLoc()); + ExprResult GetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), + RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), + GetterName, 0, true); + if (GetterExpr.isInvalid()) { + S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_getter) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + MultiExprArg ArgExprs; + return S.ActOnCallExpr(S.getCurScope(), GetterExpr.take(), + RefExpr->getSourceRange().getBegin(), ArgExprs, + RefExpr->getSourceRange().getEnd()); +} + +ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, + bool captureSetValueAsResult) { + if (!RefExpr->getPropertyDecl()->hasSetter()) { + S.Diag(RefExpr->getMemberLoc(), diag::err_no_setter_for_property) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + UnqualifiedId SetterName; + IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); + SetterName.setIdentifier(II, RefExpr->getMemberLoc()); + CXXScopeSpec SS; + SS.Adopt(RefExpr->getQualifierLoc()); + ExprResult SetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), + RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), + SetterName, 0, true); + if (SetterExpr.isInvalid()) { + S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_setter) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + SmallVector ArgExprs; + ArgExprs.push_back(op); + return S.ActOnCallExpr(S.getCurScope(), SetterExpr.take(), + RefExpr->getSourceRange().getBegin(), ArgExprs, + op->getSourceRange().getEnd()); +} + //===----------------------------------------------------------------------===// // General Sema routines. //===----------------------------------------------------------------------===// @@ -1338,6 +1438,10 @@ ExprResult Sema::checkPseudoObjectRValue(Expr *E) { = dyn_cast(opaqueRef)) { ObjCSubscriptOpBuilder builder(*this, refExpr); return builder.buildRValueOperation(E); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildRValueOperation(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1360,6 +1464,10 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, } else if (isa(opaqueRef)) { Diag(opcLoc, diag::err_illegal_container_subscripting_op); return ExprError(); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1389,6 +1497,10 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, = dyn_cast(opaqueRef)) { ObjCSubscriptOpBuilder builder(*this, refExpr); return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1414,6 +1526,10 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { OpaqueValueExpr *keyOVE = cast(refExpr->getKeyExpr()); return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(), keyOVE->getSourceExpr()).rebuild(E); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast(opaqueRef)) { + OpaqueValueExpr *baseOVE = cast(refExpr->getBaseExpr()); + return MSPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 80c452fb03..f78f4b5462 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -525,6 +525,53 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return Field; } +Decl *TemplateDeclInstantiator::VisitMSPropertyDecl(MSPropertyDecl *D) { + bool Invalid = false; + TypeSourceInfo *DI = D->getTypeSourceInfo(); + + if (DI->getType()->isVariablyModifiedType()) { + SemaRef.Diag(D->getLocation(), diag::err_property_is_variably_modified) + << D->getName(); + Invalid = true; + } else if (DI->getType()->isInstantiationDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { + DI = D->getTypeSourceInfo(); + Invalid = true; + } else if (DI->getType()->isFunctionType()) { + // C++ [temp.arg.type]p3: + // If a declaration acquires a function type through a type + // dependent on a template-parameter and this causes a + // declaration that does not use the syntactic form of a + // function declarator to have function type, the program is + // ill-formed. + SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) + << DI->getType(); + Invalid = true; + } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); + } + + MSPropertyDecl *Property = new (SemaRef.Context) + MSPropertyDecl(Owner, D->getLocation(), + D->getDeclName(), DI->getType(), DI, + D->getLocStart(), + D->getGetterId(), D->getSetterId()); + + SemaRef.InstantiateAttrs(TemplateArgs, D, Property, LateAttrs, + StartingScope); + + if (Invalid) + Property->setInvalidDecl(); + + Property->setAccess(D->getAccess()); + Owner->addDecl(Property); + + return Property; +} + Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { NamedDecl **NamedChain = new (SemaRef.Context)NamedDecl*[D->getChainingSize()]; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 81e02f5596..b4083e9bc7 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6028,6 +6028,32 @@ TreeTransform::TransformMSDependentExistsStmt( SubStmt.get()); } +template +ExprResult +TreeTransform::TransformMSPropertyRefExpr(MSPropertyRefExpr *E) { + NestedNameSpecifierLoc QualifierLoc; + if (E->getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); + if (!QualifierLoc) + return ExprError(); + } + + MSPropertyDecl *PD = cast_or_null( + getDerived().TransformDecl(E->getMemberLoc(), E->getPropertyDecl())); + if (!PD) + return ExprError(); + + ExprResult Base = getDerived().TransformExpr(E->getBaseExpr()); + if (Base.isInvalid()) + return ExprError(); + + return new (SemaRef.getASTContext()) + MSPropertyRefExpr(Base.get(), PD, E->isArrow(), + SemaRef.getASTContext().PseudoObjectTy, VK_LValue, + QualifierLoc, E->getMemberLoc()); +} + template StmtResult TreeTransform::TransformSEHTryStmt(SEHTryStmt *S) { diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 7bbe6b18f9..e8cc1553aa 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -180,6 +180,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::UnresolvedUsingValue: case Decl::IndirectField: case Decl::Field: + case Decl::MSProperty: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: case Decl::ImplicitParam: diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index cad6ea77b6..02295d09be 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -244,6 +244,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *FD); + void VisitMSPropertyDecl(MSPropertyDecl *FD); void VisitIndirectFieldDecl(IndirectFieldDecl *FD); void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); @@ -879,6 +880,12 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { } } +void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) { + VisitDeclaratorDecl(PD); + PD->GetterId = Reader.GetIdentifierInfo(F, Record, Idx); + PD->SetterId = Reader.GetIdentifierInfo(F, Record, Idx); +} + void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { VisitValueDecl(FD); @@ -2136,6 +2143,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_BLOCK: D = BlockDecl::CreateDeserialized(Context, ID); break; + case DECL_MS_PROPERTY: + D = MSPropertyDecl::CreateDeserialized(Context, ID); + break; case DECL_CXX_BASE_SPECIFIERS: Error("attempt to read a C++ base-specifier record as a declaration"); return 0; diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 078ecb7a06..567d50e71d 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1498,6 +1498,15 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements //===----------------------------------------------------------------------===// +void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + E->IsArrow = (Record[Idx++] != 0); + E->BaseExpr = Reader.ReadSubExpr(); + E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); + E->MemberLoc = ReadSourceLocation(Record, Idx); + E->TheDecl = ReadDeclAs(Record, Idx); +} + void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); E->setSourceRange(ReadSourceRange(Record, Idx)); @@ -2073,6 +2082,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_CXX_UUIDOF_EXPR: S = new (Context) CXXUuidofExpr(Empty, true); break; + case EXPR_CXX_PROPERTY_REF_EXPR: + S = new (Context) MSPropertyRefExpr(Empty); + break; case EXPR_CXX_UUIDOF_TYPE: S = new (Context) CXXUuidofExpr(Empty, false); break; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 03e33ad369..e98708d8f5 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -907,6 +907,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_OBJC_PROPERTY); RECORD(DECL_OBJC_PROPERTY_IMPL); RECORD(DECL_FIELD); + RECORD(DECL_MS_PROPERTY); RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index ef9e60f32e..7d21c584aa 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -81,6 +81,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); + void VisitMSPropertyDecl(MSPropertyDecl *D); void VisitIndirectFieldDecl(IndirectFieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -662,6 +663,13 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { Code = serialization::DECL_FIELD; } +void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *D) { + VisitDeclaratorDecl(D); + Writer.AddIdentifierRef(D->getGetterId(), Record); + Writer.AddIdentifierRef(D->getSetterId(), Record); + Code = serialization::DECL_MS_PROPERTY; +} + void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { VisitValueDecl(D); Record.push_back(D->getChainingSize()); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index b6f1d54d40..920730ffd6 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1534,6 +1534,16 @@ void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) { //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements. //===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + Record.push_back(E->isArrow()); + Writer.AddStmt(E->getBaseExpr()); + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); + Writer.AddSourceLocation(E->getMemberLoc(), Record); + Writer.AddDeclRef(E->getPropertyDecl(), Record); + Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR; +} + void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); Writer.AddSourceRange(E->getSourceRange(), Record); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 1969d947a4..cf75deb5c0 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -609,6 +609,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: + case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::UnaryTypeTraitExprClass: diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index fd38dca194..d8a597a8cc 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -331,3 +331,32 @@ namespace Inheritance { class __multiple_inheritance B; class __virtual_inheritance C; } + +struct StructWithProperty { + __declspec(property) int V0; // expected-error {{expected '(' after 'property'}} + __declspec(property()) int V1; // expected-error {{property does not specify a getter or a putter}} + __declspec(property(set)) int V2; // expected-error {{putter for property must be specified as 'put', not 'set'}} expected-error {{expected '=' after 'set'}} + __declspec(property(ptu)) int V3; // expected-error {{missing 'get=' or 'put='}} + __declspec(property(ptu=PutV)) int V4; // expected-error {{expected 'get' or 'put' in property declaration}} + __declspec(property(get)) int V5; // expected-error {{expected '=' after 'get'}} + __declspec(property(get&)) int V6; // expected-error {{expected '=' after 'get'}} + __declspec(property(get=)) int V7; // expected-error {{expected name of accessor method}} + __declspec(property(get=GetV)) int V8; // no-warning + __declspec(property(get=GetV=)) int V9; // expected-error {{expected ',' or ')' at end of property accessor list}} + __declspec(property(get=GetV,)) int V10; // expected-error {{expected 'get' or 'put' in property declaration}} + __declspec(property(get=GetV,put=SetV)) int V11; // no-warning + __declspec(property(get=GetV,put=SetV,get=GetV)) int V12; // expected-error {{property declaration specifies 'get' accessor twice}} + + int GetV() { return 123; } + void SetV(int v) {} +}; +void TestProperty() { + StructWithProperty sp; + sp.V8; + sp.V8 = 0; // expected-error {{no setter defined for property 'V8'}} + int i = sp.V11; + sp.V11 = i++; + sp.V11 += 8; + sp.V11++; + ++sp.V11; +} diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 449e24b03b..07b93face9 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -208,3 +208,127 @@ void ::f(); // expected-warning{{extra qualification on member 'f'}} class C { C::C(); // expected-warning{{extra qualification on member 'C'}} }; + +struct StructWithProperty { + __declspec(property(get=GetV)) int V1; + __declspec(property(put=SetV)) int V2; + __declspec(property(get=GetV, put=SetV_NotExist)) int V3; + __declspec(property(get=GetV_NotExist, put=SetV)) int V4; + __declspec(property(get=GetV, put=SetV)) int V5; + + int GetV() { return 123; } + void SetV(int i) {} +}; +void TestProperty() { + StructWithProperty sp; + int i = sp.V2; // expected-error{{no getter defined for property 'V2'}} + sp.V1 = 12; // expected-error{{no setter defined for property 'V1'}} + int j = sp.V4; // expected-error{{no member named 'GetV_NotExist' in 'StructWithProperty'}} expected-error{{cannot find suitable getter for property 'V4'}} + sp.V3 = 14; // expected-error{{no member named 'SetV_NotExist' in 'StructWithProperty'}} expected-error{{cannot find suitable setter for property 'V3'}} + int k = sp.V5; + sp.V5 = k++; +} + +/* 4 tests for PseudoObject, begin */ +struct SP1 +{ + bool operator()() { return true; } +}; +struct SP2 +{ + __declspec(property(get=GetV)) SP1 V; + SP1 GetV() { return SP1(); } +}; +void TestSP2() { + SP2 sp2; + bool b = sp2.V(); +} + +struct SP3 { + template + void f(T t) {} +}; +template +struct SP4 +{ + __declspec(property(get=GetV)) int V; + int GetV() { return 123; } + void f() { SP3 s2; s2.f(V); } +}; +void TestSP4() { + SP4 s; + s.f(); +} + +template +struct SP5 +{ + __declspec(property(get=GetV)) T V; + int GetV() { return 123; } + void f() { int *p = new int[V]; } +}; + +template +struct SP6 +{ +public: + __declspec(property(get=GetV)) T V; + T GetV() { return 123; } + void f() { int t = V; } +}; +void TestSP6() { + SP6 c; + c.f(); +} +/* 4 tests for PseudoObject, end */ + +// Property access: explicit, implicit, with Qualifier +struct SP7 { + __declspec(property(get=GetV, put=SetV)) int V; + int GetV() { return 123; } + void SetV(int v) {} + + void ImplicitAccess() { int i = V; V = i; } + void ExplicitAccess() { int i = this->V; this->V = i; } +}; +struct SP8: public SP7 { + void AccessWithQualifier() { int i = SP7::V; SP7::V = i; } +}; + +// Property usage +template +struct SP9 { + __declspec(property(get=GetV, put=SetV)) T V; + T GetV() { return 0; } + void SetV(T v) {} + void f() { V = this->V; V < this->V; } + //void g() { V++; } + //void h() { V*=2; } +}; +struct SP10 { + SP10(int v) {} + bool operator<(const SP10& v) { return true; } + SP10 operator*(int v) { return *this; } + SP10& operator=(const SP10& v) { return *this; } +}; +void TestSP9() { + SP9 c; + int i = c.V; // Decl initializer + i = c.V; // Binary op operand + c.SetV(c.V); // CallExpr arg + int *p = new int[c.V + 1]; // Array size + p[c.V] = 1; // Array index + + c.V = 123; // Setter + + c.V++; // Unary op operand + c.V *= 2; // Unary op operand + + SP9 c2; + c2.V[0] = 123; // Array + + SP9 c3; + c3.f(); // Overloaded binary op operand + //c3.g(); // Overloaded incdec op operand + //c3.h(); // Overloaded unary op operand +} diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m index cda983c9ec..e84fad2394 100644 --- a/test/SemaObjC/property-user-setter.m +++ b/test/SemaObjC/property-user-setter.m @@ -85,7 +85,7 @@ static int g_val; - (void)setFoo:(int)value; @end -void g(int); // expected-note {{passing argument to parameter here}} +void g(int); void f(C *c) { c.Foo = 17; // OK diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 18821aaa45..d1aeee04ea 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -4458,6 +4458,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::TemplateTypeParm: case Decl::EnumConstant: case Decl::Field: + case Decl::MSProperty: case Decl::IndirectField: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 7b01ec2de0..a413903f9a 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -442,6 +442,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::MemberExprClass: + case Stmt::MSPropertyRefExprClass: case Stmt::ObjCIsaExprClass: case Stmt::ObjCIvarRefExprClass: case Stmt::ObjCPropertyRefExprClass: diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp index 95d74efc04..54711e6332 100644 --- a/tools/libclang/IndexBody.cpp +++ b/tools/libclang/IndexBody.cpp @@ -89,6 +89,12 @@ public: return true; } + bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(), Parent, + ParentDC, E, CXIdxEntityRef_Direct); + return true; + } + bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) { IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(), Parent, ParentDC, E, CXIdxEntityRef_Direct); diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp index d7fb959b1e..756001c3c1 100644 --- a/tools/libclang/IndexDecl.cpp +++ b/tools/libclang/IndexDecl.cpp @@ -105,6 +105,11 @@ public: return true; } + bool VisitMSPropertyDecl(const MSPropertyDecl *D) { + handleDeclarator(D); + return true; + } + bool VisitEnumConstantDecl(const EnumConstantDecl *D) { IndexCtx.handleEnumerator(D); IndexCtx.indexBody(D->getInitExpr(), D); diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp index 336892250e..14b430c7dc 100644 --- a/tools/libclang/IndexingContext.cpp +++ b/tools/libclang/IndexingContext.cpp @@ -396,6 +396,12 @@ bool IndexingContext::handleField(const FieldDecl *D) { return handleDecl(D, D->getLocation(), getCursor(D), DInfo); } +bool IndexingContext::handleMSProperty(const MSPropertyDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + bool IndexingContext::handleEnumerator(const EnumConstantDecl *D) { DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, /*isContainer=*/false); diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h index c9097c5e6e..62873bedb2 100644 --- a/tools/libclang/IndexingContext.h +++ b/tools/libclang/IndexingContext.h @@ -16,6 +16,7 @@ namespace clang { class FileEntry; + class MSPropertyDecl; class ObjCPropertyDecl; class ClassTemplateDecl; class FunctionTemplateDecl; @@ -404,6 +405,8 @@ public: bool handleField(const FieldDecl *D); + bool handleMSProperty(const MSPropertyDecl *D); + bool handleEnumerator(const EnumConstantDecl *D); bool handleTagDecl(const TagDecl *D); diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h index 5862e12cd1..0312f1fbbd 100644 --- a/tools/libclang/RecursiveASTVisitor.h +++ b/tools/libclang/RecursiveASTVisitor.h @@ -1614,6 +1614,10 @@ DEF_TRAVERSE_DECL(FieldDecl, { TRY_TO(TraverseStmt(D->getInClassInitializer())); }) +DEF_TRAVERSE_DECL(MSPropertyDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + }) + DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, { TRY_TO(TraverseDeclaratorHelper(D)); if (D->isBitField()) @@ -2133,6 +2137,7 @@ DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { } }) +DEF_TRAVERSE_STMT(MSPropertyRefExpr, {}) DEF_TRAVERSE_STMT(SEHTryStmt, {}) DEF_TRAVERSE_STMT(SEHExceptStmt, {}) DEF_TRAVERSE_STMT(SEHFinallyStmt,{}) -- 2.40.0