Index: cfe/trunk/include/clang/AST/ExprCXX.h =================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h +++ cfe/trunk/include/clang/AST/ExprCXX.h @@ -677,6 +677,69 @@ friend class ASTStmtReader; }; +/// MS property subscript expression. +/// MSVC supports 'property' attribute and allows to apply it to the +/// declaration of an empty array in a class or structure definition. +/// For example: +/// \code +/// __declspec(property(get=GetX, put=PutX)) int x[]; +/// \endcode +/// The above statement indicates that x[] can be used with one or more array +/// indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), and +/// p->x[a][b] = i will be turned into p->PutX(a, b, i). +/// This is a syntactic pseudo-object expression. +class MSPropertySubscriptExpr : public Expr { + friend class ASTStmtReader; + enum { BASE_EXPR, IDX_EXPR, NUM_SUBEXPRS = 2 }; + Stmt *SubExprs[NUM_SUBEXPRS]; + SourceLocation RBracketLoc; + + void setBase(Expr *Base) { SubExprs[BASE_EXPR] = Base; } + void setIdx(Expr *Idx) { SubExprs[IDX_EXPR] = Idx; } + +public: + MSPropertySubscriptExpr(Expr *Base, Expr *Idx, QualType Ty, ExprValueKind VK, + ExprObjectKind OK, SourceLocation RBracketLoc) + : Expr(MSPropertySubscriptExprClass, Ty, VK, OK, Idx->isTypeDependent(), + Idx->isValueDependent(), Idx->isInstantiationDependent(), + Idx->containsUnexpandedParameterPack()), + RBracketLoc(RBracketLoc) { + SubExprs[BASE_EXPR] = Base; + SubExprs[IDX_EXPR] = Idx; + } + + /// \brief Create an empty array subscript expression. + explicit MSPropertySubscriptExpr(EmptyShell Shell) + : Expr(MSPropertySubscriptExprClass, Shell) {} + + Expr *getBase() { return cast(SubExprs[BASE_EXPR]); } + const Expr *getBase() const { return cast(SubExprs[BASE_EXPR]); } + + Expr *getIdx() { return cast(SubExprs[IDX_EXPR]); } + const Expr *getIdx() const { return cast(SubExprs[IDX_EXPR]); } + + SourceLocation getLocStart() const LLVM_READONLY { + return getBase()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getBase()->getExprLoc(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSPropertySubscriptExprClass; + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0] + NUM_SUBEXPRS); + } +}; + /// A Microsoft C++ @c __uuidof expression, which gets /// the _GUID that corresponds to the supplied type or expression. /// Index: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h @@ -2112,6 +2112,8 @@ TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); }) +DEF_TRAVERSE_STMT(MSPropertySubscriptExpr, {}) + DEF_TRAVERSE_STMT(CXXUuidofExpr, { // The child-iterator will pick up the arg if it's an expression, // but not if it's a type. Index: cfe/trunk/include/clang/Basic/StmtNodes.td =================================================================== --- cfe/trunk/include/clang/Basic/StmtNodes.td +++ cfe/trunk/include/clang/Basic/StmtNodes.td @@ -180,6 +180,7 @@ // Microsoft Extensions. def MSPropertyRefExpr : DStmt; +def MSPropertySubscriptExpr : DStmt; def CXXUuidofExpr : DStmt; def SEHTryStmt : Stmt; def SEHExceptStmt : Stmt; Index: cfe/trunk/include/clang/Serialization/ASTBitCodes.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h @@ -1413,6 +1413,7 @@ // Microsoft EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr + EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). STMT_SEH_LEAVE, // SEHLeaveStmt Index: cfe/trunk/lib/AST/Expr.cpp =================================================================== --- cfe/trunk/lib/AST/Expr.cpp +++ cfe/trunk/lib/AST/Expr.cpp @@ -3004,6 +3004,7 @@ return true; case MSPropertyRefExprClass: + case MSPropertySubscriptExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: Index: cfe/trunk/lib/AST/ExprClassification.cpp =================================================================== --- cfe/trunk/lib/AST/ExprClassification.cpp +++ cfe/trunk/lib/AST/ExprClassification.cpp @@ -136,6 +136,7 @@ case Expr::ObjCIvarRefExprClass: case Expr::FunctionParmPackExprClass: case Expr::MSPropertyRefExprClass: + case Expr::MSPropertySubscriptExprClass: case Expr::OMPArraySectionExprClass: return Cl::CL_LValue; Index: cfe/trunk/lib/AST/ExprConstant.cpp =================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp +++ cfe/trunk/lib/AST/ExprConstant.cpp @@ -8974,6 +8974,7 @@ case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: case Expr::MSPropertyRefExprClass: + case Expr::MSPropertySubscriptExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: Index: cfe/trunk/lib/AST/ItaniumMangle.cpp =================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp +++ cfe/trunk/lib/AST/ItaniumMangle.cpp @@ -2811,6 +2811,7 @@ case Expr::ParenListExprClass: case Expr::LambdaExprClass: case Expr::MSPropertyRefExprClass: + case Expr::MSPropertySubscriptExprClass: case Expr::TypoExprClass: // This should no longer exist in the AST by now. case Expr::OMPArraySectionExprClass: llvm_unreachable("unexpected statement kind"); Index: cfe/trunk/lib/AST/StmtPrinter.cpp =================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp +++ cfe/trunk/lib/AST/StmtPrinter.cpp @@ -1738,6 +1738,13 @@ OS << Node->getPropertyDecl()->getDeclName(); } +void StmtPrinter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *Node) { + PrintExpr(Node->getBase()); + OS << "["; + PrintExpr(Node->getIdx()); + OS << "]"; +} + void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { switch (Node->getLiteralOperatorKind()) { case UserDefinedLiteral::LOK_Raw: Index: cfe/trunk/lib/AST/StmtProfile.cpp =================================================================== --- cfe/trunk/lib/AST/StmtProfile.cpp +++ cfe/trunk/lib/AST/StmtProfile.cpp @@ -1129,6 +1129,11 @@ VisitDecl(S->getPropertyDecl()); } +void StmtProfiler::VisitMSPropertySubscriptExpr( + const MSPropertySubscriptExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); ID.AddBoolean(S->isImplicit()); Index: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp @@ -1179,6 +1179,7 @@ return CT_Cannot; case Expr::MSPropertyRefExprClass: + case Expr::MSPropertySubscriptExprClass: llvm_unreachable("Invalid class for expression"); #define STMT(CLASS, PARENT) case Expr::CLASS##Class: Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -3901,6 +3901,13 @@ return true; } +static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) { + auto *BaseNoParens = Base->IgnoreParens(); + if (auto *MSProp = dyn_cast(BaseNoParens)) + return MSProp->getPropertyDecl()->getType()->isArrayType(); + return isa(BaseNoParens); +} + ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, Expr *idx, SourceLocation rbLoc) { @@ -3921,10 +3928,15 @@ // operand might be an overloadable type, in which case the overload // resolution for the operator overload should get the first crack // at the overload. + bool IsMSPropertySubscript = false; if (base->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(base); - if (result.isInvalid()) return ExprError(); - base = result.get(); + IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base); + if (!IsMSPropertySubscript) { + ExprResult result = CheckPlaceholderExpr(base); + if (result.isInvalid()) + return ExprError(); + base = result.get(); + } } if (idx->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(idx); @@ -3939,6 +3951,21 @@ VK_LValue, OK_Ordinary, rbLoc); } + // MSDN, property (C++) + // https://msdn.microsoft.com/en-us/library/yhfk0thd(v=vs.120).aspx + // This attribute can also be used in the declaration of an empty array in a + // class or structure definition. For example: + // __declspec(property(get=GetX, put=PutX)) int x[]; + // The above statement indicates that x[] can be used with one or more array + // indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), + // and p->x[a][b] = i will be turned into p->PutX(a, b, i); + if (IsMSPropertySubscript) { + // Build MS property subscript expression if base is MS property reference + // or MS property subscript. + return new (Context) MSPropertySubscriptExpr( + base, idx, Context.PseudoObjectTy, VK_LValue, OK_Ordinary, rbLoc); + } + // Use C++ overloaded-operator rules if either operand has record // type. The spec says to do this if either type is *overloadable*, // but enum types can't declare subscript operators or conversion Index: cfe/trunk/lib/Sema/SemaPseudoObject.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaPseudoObject.cpp +++ cfe/trunk/lib/Sema/SemaPseudoObject.cpp @@ -44,17 +44,76 @@ namespace { // Basically just a very focused copy of TreeTransform. - template struct Rebuilder { + struct Rebuilder { Sema &S; - Rebuilder(Sema &S) : S(S) {} + unsigned MSPropertySubscriptCount; + typedef llvm::function_ref SpecificRebuilderRefTy; + const SpecificRebuilderRefTy &SpecificCallback; + Rebuilder(Sema &S, const SpecificRebuilderRefTy &SpecificCallback) + : S(S), MSPropertySubscriptCount(0), + SpecificCallback(SpecificCallback) {} - T &getDerived() { return static_cast(*this); } + Expr *rebuildObjCPropertyRefExpr(ObjCPropertyRefExpr *refExpr) { + // Fortunately, the constraint that we're rebuilding something + // with a base limits the number of cases here. + if (refExpr->isClassReceiver() || refExpr->isSuperReceiver()) + return refExpr; + + if (refExpr->isExplicitProperty()) { + return new (S.Context) ObjCPropertyRefExpr( + refExpr->getExplicitProperty(), refExpr->getType(), + refExpr->getValueKind(), refExpr->getObjectKind(), + refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0)); + } + return new (S.Context) ObjCPropertyRefExpr( + refExpr->getImplicitPropertyGetter(), + refExpr->getImplicitPropertySetter(), refExpr->getType(), + refExpr->getValueKind(), refExpr->getObjectKind(), + refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0)); + } + Expr *rebuildObjCSubscriptRefExpr(ObjCSubscriptRefExpr *refExpr) { + assert(refExpr->getBaseExpr()); + assert(refExpr->getKeyExpr()); + + return new (S.Context) ObjCSubscriptRefExpr( + SpecificCallback(refExpr->getBaseExpr(), 0), + SpecificCallback(refExpr->getKeyExpr(), 1), refExpr->getType(), + refExpr->getValueKind(), refExpr->getObjectKind(), + refExpr->getAtIndexMethodDecl(), refExpr->setAtIndexMethodDecl(), + refExpr->getRBracket()); + } + Expr *rebuildMSPropertyRefExpr(MSPropertyRefExpr *refExpr) { + assert(refExpr->getBaseExpr()); + + return new (S.Context) MSPropertyRefExpr( + SpecificCallback(refExpr->getBaseExpr(), 0), + refExpr->getPropertyDecl(), refExpr->isArrow(), refExpr->getType(), + refExpr->getValueKind(), refExpr->getQualifierLoc(), + refExpr->getMemberLoc()); + } + Expr *rebuildMSPropertySubscriptExpr(MSPropertySubscriptExpr *refExpr) { + assert(refExpr->getBase()); + assert(refExpr->getIdx()); + + auto *NewBase = rebuild(refExpr->getBase()); + ++MSPropertySubscriptCount; + return new (S.Context) MSPropertySubscriptExpr( + NewBase, + SpecificCallback(refExpr->getIdx(), MSPropertySubscriptCount), + refExpr->getType(), refExpr->getValueKind(), refExpr->getObjectKind(), + refExpr->getRBracketLoc()); + } Expr *rebuild(Expr *e) { // Fast path: nothing to look through. - if (typename T::specific_type *specific - = dyn_cast(e)) - return getDerived().rebuildSpecific(specific); + if (auto *PRE = dyn_cast(e)) + return rebuildObjCPropertyRefExpr(PRE); + if (auto *SRE = dyn_cast(e)) + return rebuildObjCSubscriptRefExpr(SRE); + if (auto *MSPRE = dyn_cast(e)) + return rebuildMSPropertyRefExpr(MSPRE); + if (auto *MSPSE = dyn_cast(e)) + return rebuildMSPropertySubscriptExpr(MSPSE); // Otherwise, we should look through and rebuild anything that // IgnoreParens would. @@ -125,72 +184,6 @@ } }; - struct ObjCPropertyRefRebuilder : Rebuilder { - Expr *NewBase; - ObjCPropertyRefRebuilder(Sema &S, Expr *newBase) - : Rebuilder(S), NewBase(newBase) {} - - typedef ObjCPropertyRefExpr specific_type; - Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) { - // Fortunately, the constraint that we're rebuilding something - // with a base limits the number of cases here. - assert(refExpr->isObjectReceiver()); - - if (refExpr->isExplicitProperty()) { - return new (S.Context) - ObjCPropertyRefExpr(refExpr->getExplicitProperty(), - refExpr->getType(), refExpr->getValueKind(), - refExpr->getObjectKind(), refExpr->getLocation(), - NewBase); - } - return new (S.Context) - ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(), - refExpr->getImplicitPropertySetter(), - refExpr->getType(), refExpr->getValueKind(), - refExpr->getObjectKind(),refExpr->getLocation(), - NewBase); - } - }; - - struct ObjCSubscriptRefRebuilder : Rebuilder { - Expr *NewBase; - Expr *NewKeyExpr; - ObjCSubscriptRefRebuilder(Sema &S, Expr *newBase, Expr *newKeyExpr) - : Rebuilder(S), - NewBase(newBase), NewKeyExpr(newKeyExpr) {} - - typedef ObjCSubscriptRefExpr specific_type; - Expr *rebuildSpecific(ObjCSubscriptRefExpr *refExpr) { - assert(refExpr->getBaseExpr()); - assert(refExpr->getKeyExpr()); - - return new (S.Context) - ObjCSubscriptRefExpr(NewBase, - NewKeyExpr, - refExpr->getType(), refExpr->getValueKind(), - refExpr->getObjectKind(),refExpr->getAtIndexMethodDecl(), - refExpr->setAtIndexMethodDecl(), - 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: Sema &S; @@ -329,11 +322,19 @@ class MSPropertyOpBuilder : public PseudoOpBuilder { MSPropertyRefExpr *RefExpr; OpaqueValueExpr *InstanceBase; + SmallVector CallArgs; + + MSPropertyRefExpr *getBaseMSProperty(MSPropertySubscriptExpr *E); public: MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), RefExpr(refExpr), InstanceBase(nullptr) {} + MSPropertyOpBuilder(Sema &S, MSPropertySubscriptExpr *refExpr) + : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), + InstanceBase(nullptr) { + RefExpr = getBaseMSProperty(refExpr); + } Expr *rebuildAndCaptureObject(Expr *) override; ExprResult buildGet() override; @@ -674,9 +675,9 @@ // form to use the OVE as its base. if (RefExpr->isObjectReceiver()) { InstanceReceiver = capture(RefExpr->getBase()); - - syntacticBase = - ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase); + syntacticBase = Rebuilder(S, [=](Expr *, unsigned) -> Expr * { + return InstanceReceiver; + }).rebuild(syntacticBase); } if (ObjCPropertyRefExpr * @@ -994,11 +995,19 @@ // form to use the OVE as its base expression. InstanceBase = capture(RefExpr->getBaseExpr()); InstanceKey = capture(RefExpr->getKeyExpr()); - + syntacticBase = - ObjCSubscriptRefRebuilder(S, InstanceBase, - InstanceKey).rebuild(syntacticBase); - + Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * { + switch (Idx) { + case 0: + return InstanceBase; + case 1: + return InstanceKey; + default: + llvm_unreachable("Unexpected index for ObjCSubscriptExpr"); + } + }).rebuild(syntacticBase); + return syntacticBase; } @@ -1400,11 +1409,30 @@ // MSVC __declspec(property) references //===----------------------------------------------------------------------===// +MSPropertyRefExpr * +MSPropertyOpBuilder::getBaseMSProperty(MSPropertySubscriptExpr *E) { + CallArgs.insert(CallArgs.begin(), E->getIdx()); + Expr *Base = E->getBase()->IgnoreParens(); + while (auto *MSPropSubscript = dyn_cast(Base)) { + CallArgs.insert(CallArgs.begin(), MSPropSubscript->getIdx()); + Base = MSPropSubscript->getBase()->IgnoreParens(); + } + return cast(Base); +} + Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { InstanceBase = capture(RefExpr->getBaseExpr()); - - syntacticBase = - MSPropertyRefRebuilder(S, InstanceBase).rebuild(syntacticBase); + std::for_each(CallArgs.begin(), CallArgs.end(), + [this](Expr *&Arg) { Arg = capture(Arg); }); + syntacticBase = Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * { + switch (Idx) { + case 0: + return InstanceBase; + default: + assert(Idx <= CallArgs.size()); + return CallArgs[Idx - 1]; + } + }).rebuild(syntacticBase); return syntacticBase; } @@ -1432,9 +1460,8 @@ return ExprError(); } - MultiExprArg ArgExprs; return S.ActOnCallExpr(S.getCurScope(), GetterExpr.get(), - RefExpr->getSourceRange().getBegin(), ArgExprs, + RefExpr->getSourceRange().getBegin(), CallArgs, RefExpr->getSourceRange().getEnd()); } @@ -1462,7 +1489,8 @@ return ExprError(); } - SmallVector ArgExprs; + SmallVector ArgExprs; + ArgExprs.append(CallArgs.begin(), CallArgs.end()); ArgExprs.push_back(op); return S.ActOnCallExpr(S.getCurScope(), SetterExpr.get(), RefExpr->getSourceRange().getBegin(), ArgExprs, @@ -1488,6 +1516,10 @@ = dyn_cast(opaqueRef)) { MSPropertyOpBuilder builder(*this, refExpr); return builder.buildRValueOperation(E); + } else if (MSPropertySubscriptExpr *RefExpr = + dyn_cast(opaqueRef)) { + MSPropertyOpBuilder Builder(*this, RefExpr); + return Builder.buildRValueOperation(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1514,6 +1546,10 @@ = dyn_cast(opaqueRef)) { MSPropertyOpBuilder builder(*this, refExpr); return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); + } else if (MSPropertySubscriptExpr *RefExpr + = dyn_cast(opaqueRef)) { + MSPropertyOpBuilder Builder(*this, RefExpr); + return Builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1545,8 +1581,12 @@ 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); + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); + } else if (MSPropertySubscriptExpr *RefExpr + = dyn_cast(opaqueRef)) { + MSPropertyOpBuilder Builder(*this, RefExpr); + return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1556,29 +1596,11 @@ /// values. Basically, undo the behavior of rebuildAndCaptureObject. /// This should never operate in-place. static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { - Expr *opaqueRef = E->IgnoreParens(); - if (ObjCPropertyRefExpr *refExpr - = dyn_cast(opaqueRef)) { - // Class and super property references don't have opaque values in them. - if (refExpr->isClassReceiver() || refExpr->isSuperReceiver()) - return E; - - assert(refExpr->isObjectReceiver() && "Unknown receiver kind?"); - OpaqueValueExpr *baseOVE = cast(refExpr->getBase()); - return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); - } else if (ObjCSubscriptRefExpr *refExpr - = dyn_cast(opaqueRef)) { - OpaqueValueExpr *baseOVE = cast(refExpr->getBaseExpr()); - 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!"); - } + return Rebuilder(S, + [=](Expr *E, unsigned) -> Expr * { + return cast(E)->getSourceExpr(); + }) + .rebuild(E); } /// Given a pseudo-object expression, recreate what it looks like Index: cfe/trunk/lib/Sema/TreeTransform.h =================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h +++ cfe/trunk/lib/Sema/TreeTransform.h @@ -6919,6 +6919,25 @@ } template +ExprResult TreeTransform::TransformMSPropertySubscriptExpr( + MSPropertySubscriptExpr *E) { + auto BaseRes = getDerived().TransformExpr(E->getBase()); + if (BaseRes.isInvalid()) + return ExprError(); + auto IdxRes = getDerived().TransformExpr(E->getIdx()); + if (IdxRes.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + BaseRes.get() == E->getBase() && + IdxRes.get() == E->getIdx()) + return E; + + return getDerived().RebuildArraySubscriptExpr( + BaseRes.get(), SourceLocation(), IdxRes.get(), E->getRBracketLoc()); +} + +template StmtResult TreeTransform::TransformSEHTryStmt(SEHTryStmt *S) { StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock()); if (TryBlock.isInvalid()) Index: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp @@ -1662,6 +1662,13 @@ E->TheDecl = ReadDeclAs(Record, Idx); } +void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { + VisitExpr(E); + E->setBase(Reader.ReadSubExpr()); + E->setIdx(Reader.ReadSubExpr()); + E->setRBracketLoc(ReadSourceLocation(Record, Idx)); +} + void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); E->setSourceRange(ReadSourceRange(Record, Idx)); @@ -3086,6 +3093,9 @@ case EXPR_CXX_PROPERTY_REF_EXPR: S = new (Context) MSPropertyRefExpr(Empty); break; + case EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR: + S = new (Context) MSPropertySubscriptExpr(Empty); + break; case EXPR_CXX_UUIDOF_TYPE: S = new (Context) CXXUuidofExpr(Empty, false); break; Index: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp @@ -1689,6 +1689,14 @@ Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR; } +void ASTStmtWriter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getBase()); + Writer.AddStmt(E->getIdx()); + Writer.AddSourceLocation(E->getRBracketLoc(), Record); + Code = serialization::EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR; +} + void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); Writer.AddSourceRange(E->getSourceRange(), Record); Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -755,6 +755,7 @@ case Stmt::CXXUuidofExprClass: case Stmt::CXXFoldExprClass: case Stmt::MSPropertyRefExprClass: + case Stmt::MSPropertySubscriptExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::ArrayTypeTraitExprClass: Index: cfe/trunk/test/CodeGenCXX/ms-property.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/ms-property.cpp +++ cfe/trunk/test/CodeGenCXX/ms-property.cpp @@ -1,8 +1,15 @@ // RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER class Test1 { private: int x_; + double y_; public: Test1(int x) : x_(x) {} @@ -11,9 +18,94 @@ static Test1 *GetTest1() { return new Test1(10); } }; +class S { +public: + __declspec(property(get=GetX,put=PutX)) int x[]; + int GetX(int i, int j) { return i+j; } + void PutX(int i, int j, int k) { j = i = k; } +}; + +template +class St { +public: + __declspec(property(get=GetX,put=PutX)) T x[]; + T GetX(T i, T j) { return i+j; } + T GetX() { return 0; } + void PutX(T i, T j, T k) { j = i = k; } + __declspec(property(get=GetY,put=PutY)) T y[]; + char GetY(char i, Test1 j) { return i+j.get_x(); } + void PutY(char i, int j, double k) { j = i = k; } +}; + +template +void foo(T i, T j) { + St bar; + Test1 t(i); + bar.x[i][j] = bar.x[i][j]; + bar.y[t.X][j] = bar.x[i][j]; + bar.x[i][j] = bar.y[bar.x[i][j]][t]; +} + +int idx() { return 7; } + // CHECK-LABEL: main int main(int argc, char **argv) { + Test1 t(argc); + S *p1 = 0; + St *p2 = 0; + // CHECK: call i32 @"\01?GetX@S@@QEAAHHH@Z"(%class.S* %{{.+}}, i32 223, i32 11) + int j = p1->x[223][11]; + // CHECK: [[J:%.+]] = load i32, i32* % + // CHECK-NEXT: call void @"\01?PutX@S@@QEAAXHHH@Z"(%class.S* %{{.+}}, i32 23, i32 1, i32 [[J]]) + p1->x[23][1] = j; + // CHECK: call float @"\01?GetX@?$St@M@@QEAAMMM@Z"(%class.St* %{{.+}}, float 2.230000e+02, float 1.100000e+01) + float j1 = p2->x[223][11]; + // CHECK: [[J1:%.+]] = load float, float* % + // CHECK-NEXT: call void @"\01?PutX@?$St@M@@QEAAXMMM@Z"(%class.St* %{{.+}}, float 2.300000e+01, float 1.000000e+00, float [[J1]]) + p2->x[23][1] = j1; + // CHECK: [[IDX:%.+]] = call i32 @"\01?idx@@YAHXZ"() + // CHECK-NEXT: [[CONV:%.+]] = sitofp i32 [[IDX]] to float + // CHECK-NEXT: [[GET:%.+]] = call float @"\01?GetX@?$St@M@@QEAAMMM@Z"(%class.St* %{{.+}}, float [[CONV]], float 1.000000e+00) + // CHECK-NEXT: [[INC:%.+]] = fadd float [[GET]], 1.000000e+00 + // CHECK-NEXT: [[CONV:%.+]] = sitofp i32 [[IDX]] to float + // CHECK-NEXT: call void @"\01?PutX@?$St@M@@QEAAXMMM@Z"(%class.St* %{{.+}}, float [[CONV]], float 1.000000e+00, float [[INC]]) + ++p2->x[idx()][1]; + // CHECK: call void @"\01??$foo@H@@YAXHH@Z"(i32 %{{.+}}, i32 %{{.+}}) + foo(argc, (int)argv[0][0]); + // CHECK: [[P2:%.+]] = load %class.St*, %class.St** % + // CHECK: [[T_X:%.+]] = call i32 @"\01?get_x@Test1@@QEBAHXZ"(%class.Test1* %{{.+}}) + // CHECK: [[P1:%.+]] = load %class.S*, %class.S** % + // CHECK: [[P1_X_22_33:%.+]] = call i32 @"\01?GetX@S@@QEAAHHH@Z"(%class.S* [[P1]], i32 22, i32 33) + // CHECK: [[CAST:%.+]] = sitofp i32 [[P1_X_22_33]] to double + // CHECK: [[ARGC:%.+]] = load i32, i32* % + // CHECK: [[CAST2:%.+]] = trunc i32 [[T_X]] to i8 + // CHECK: call void @"\01?PutY@?$St@M@@QEAAXDHN@Z"(%class.St* [[P2]], i8 [[CAST2]], i32 [[ARGC]], double [[CAST]]) + p2->y[t.X][argc] = p1->x[22][33]; + // CHECK: [[P2_1:%.+]] = load %class.St*, %class.St** + // CHECK: [[P2_2:%.+]] = load %class.St*, %class.St** + // CHECK: [[P1:%.+]] = load %class.S*, %class.S** + // CHECK: [[ARGC:%.+]] = load i32, i32* % + // CHECK: [[P1_X_ARGC_0:%.+]] = call i32 @"\01?GetX@S@@QEAAHHH@Z"(%class.S* [[P1]], i32 [[ARGC]], i32 0) + // CHECK: [[CAST:%.+]] = trunc i32 [[P1_X_ARGC_0]] to i8 + // CHECK: [[P2_Y_p1_X_ARGC_0_T:%.+]] = call i8 @"\01?GetY@?$St@M@@QEAADDVTest1@@@Z"(%class.St* [[P2_2]], i8 [[CAST]], %class.Test1* %{{.+}}) + // CHECK: [[CAST:%.+]] = sitofp i8 [[P2_Y_p1_X_ARGC_0_T]] to float + // CHECK: [[J:%.+]] = load i32, i32* % + // CHECK: [[CAST1:%.+]] = sitofp i32 [[J]] to float + // CHECK: [[J:%.+]] = load i32, i32* % + // CHECK: [[CAST2:%.+]] = sitofp i32 [[J]] to float + // CHECK: call void @"\01?PutX@?$St@M@@QEAAXMMM@Z"(%class.St* [[P2_1]], float [[CAST2]], float [[CAST1]], float [[CAST]]) + p2->x[j][j] = p2->y[p1->x[argc][0]][t]; // CHECK: [[CALL:%.+]] = call %class.Test1* @"\01?GetTest1@Test1@@SAPEAV1@XZ"() // CHECK-NEXT: call i32 @"\01?get_x@Test1@@QEBAHXZ"(%class.Test1* [[CALL]]) return Test1::GetTest1()->X; } + +// CHECK: define linkonce_odr void @"\01??$foo@H@@YAXHH@Z"(i32 %{{.+}}, i32 %{{.+}}) +// CHECK: call i32 @"\01?GetX@?$St@H@@QEAAHHH@Z"(%class.St{{.+}}* [[BAR:%.+]], i32 %{{.+}} i32 %{{.+}}) +// CHECK: call void @"\01?PutX@?$St@H@@QEAAXHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}}, i32 %{{.+}}, i32 %{{.+}}) +// CHECK: call i32 @"\01?GetX@?$St@H@@QEAAHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}} i32 %{{.+}}) +// CHECK: call void @"\01?PutY@?$St@H@@QEAAXDHN@Z"(%class.St{{.+}}* [[BAR]], i8 %{{.+}}, i32 %{{.+}}, double %{{.+}} +// CHECK: call i32 @"\01?GetX@?$St@H@@QEAAHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}} i32 %{{.+}}) +// CHECK: call i8 @"\01?GetY@?$St@H@@QEAADDVTest1@@@Z"(%class.St{{.+}}* [[BAR]], i8 %{{.+}}, %class.Test1* %{{.+}}) +// CHECK: call void @"\01?PutX@?$St@H@@QEAAXHHH@Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}}, i32 %{{.+}}, i32 %{{.+}}) +#endif //HEADER Index: cfe/trunk/test/SemaCXX/ms-property-error.cpp =================================================================== --- cfe/trunk/test/SemaCXX/ms-property-error.cpp +++ cfe/trunk/test/SemaCXX/ms-property-error.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -verify -fms-compatibility %s -fsyntax-only -o - + +class S { +public: + __declspec(property(get=GetX,put=PutX)) int x[]; + int GetX(int i, int j) { return i+j; } // expected-note {{'GetX' declared here}} + void PutX(int i, int j, int k) { j = i = k; } // expected-note {{'PutX' declared here}} +}; + +template +class St { +public: + __declspec(property(get=GetX,put=PutX)) T x[]; + T GetX(T i, T j) { return i+j; } // expected-note 3 {{'GetX' declared here}} + void PutX(T i, T j, T k) { j = i = k; } // expected-note 2 {{'PutX' declared here}} + ~St() { + x[1] = 0; // expected-error {{too few arguments to function call, expected 3, have 2}} + x[2][3] = 4; + ++x[2][3]; + x[1][2] = x[3][4][5]; // expected-error {{too many arguments to function call, expected 2, have 3}} + } +}; + +// CHECK-LABEL: main +int main(int argc, char **argv) { + S *p1 = 0; + St *p2 = 0; + St a; // expected-note {{in instantiation of member function 'St::~St' requested here}} + int j = (p1->x)[223][11][2]; // expected-error {{too many arguments to function call, expected 2, have 3}} + (p1->x[23]) = argc; // expected-error {{too few arguments to function call, expected 3, have 2}} + float j1 = (p2->x); // expected-error {{too few arguments to function call, expected 2, have 0}} + ((p2->x)[23])[1][2] = *argv; // expected-error {{too many arguments to function call, expected 3, have 4}} + return ++(((p2->x)[23])); // expected-error {{too few arguments to function call, expected 2, have 1}} +} Index: cfe/trunk/test/SemaCXX/ms-property.cpp =================================================================== --- cfe/trunk/test/SemaCXX/ms-property.cpp +++ cfe/trunk/test/SemaCXX/ms-property.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -ast-print -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +class Test1 { +private: + int x_; + +public: + Test1(int x) : x_(x) {} + __declspec(property(get = get_x)) int X; + int get_x() const { return x_; } + static Test1 *GetTest1() { return new Test1(10); } +}; + +class S { +public: + __declspec(property(get=GetX,put=PutX)) int x[]; + int GetX(int i, int j) { return i+j; } + void PutX(int i, int j, int k) { j = i = k; } +}; + +template +class St { +public: + __declspec(property(get=GetX,put=PutX)) T x[]; + T GetX(T i, T j) { return i+j; } + void PutX(T i, T j, T k) { j = i = k; } + ~St() { x[0][0] = x[1][1]; } +}; + +// CHECK: this->x[0][0] = this->x[1][1]; +// CHECK: this->x[0][0] = this->x[1][1]; + +// CHECK-LABEL: main +int main(int argc, char **argv) { + S *p1 = 0; + St *p2 = 0; + // CHECK: St a; + St a; + // CHECK-NEXT: int j = (p1->x)[223][11]; + int j = (p1->x)[223][11]; + // CHECK-NEXT: (p1->x[23])[1] = j; + (p1->x[23])[1] = j; + // CHECK-NEXT: float j1 = (p2->x[223][11]); + float j1 = (p2->x[223][11]); + // CHECK-NEXT: ((p2->x)[23])[1] = j1; + ((p2->x)[23])[1] = j1; + // CHECK-NEXT: ++(((p2->x)[23])[1]); + ++(((p2->x)[23])[1]); + // CHECK-NEXT: return Test1::GetTest1()->X; + return Test1::GetTest1()->X; +} +#endif // HEADER Index: cfe/trunk/tools/libclang/CXCursor.cpp =================================================================== --- cfe/trunk/tools/libclang/CXCursor.cpp +++ cfe/trunk/tools/libclang/CXCursor.cpp @@ -329,6 +329,7 @@ K = CXCursor_UnaryExpr; break; + case Stmt::MSPropertySubscriptExprClass: case Stmt::ArraySubscriptExprClass: K = CXCursor_ArraySubscriptExpr; break;