Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2120,6 +2120,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: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -677,6 +677,68 @@ friend class ASTStmtReader; }; +/// \brief 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). +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: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2160,6 +2160,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: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -171,6 +171,7 @@ // Microsoft Extensions. def MSPropertyRefExpr : DStmt; +def MSPropertySubscriptExpr : DStmt; def CXXUuidofExpr : DStmt; def SEHTryStmt : Stmt; def SEHExceptStmt : Stmt; Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1398,6 +1398,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: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -2998,6 +2998,7 @@ return true; case MSPropertyRefExprClass: + case MSPropertySubscriptExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ 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: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8972,6 +8972,7 @@ case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: case Expr::MSPropertyRefExprClass: + case Expr::MSPropertySubscriptExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2809,6 +2809,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: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -1715,6 +1715,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: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -1123,6 +1123,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: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1177,6 +1177,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: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3917,7 +3917,13 @@ // operand might be an overloadable type, in which case the overload // resolution for the operator overload should get the first crack // at the overload. - if (base->getType()->isNonOverloadPlaceholderType()) { + auto *MSProp = dyn_cast(base->IgnoreParens()); + bool IsMSPropertySubscript = + getLangOpts().CPlusPlus && + ((MSProp && MSProp->getPropertyDecl()->getType()->isArrayType()) || + isa(base->IgnoreParens())); + if (base->getType()->isNonOverloadPlaceholderType() && + !IsMSPropertySubscript) { ExprResult result = CheckPlaceholderExpr(base); if (result.isInvalid()) return ExprError(); base = result.get(); @@ -3935,6 +3941,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: lib/Sema/SemaPseudoObject.cpp =================================================================== --- lib/Sema/SemaPseudoObject.cpp +++ lib/Sema/SemaPseudoObject.cpp @@ -121,6 +121,12 @@ rebuiltExpr->isValueDependent()); } + if (MSPropertySubscriptExpr *PSE = dyn_cast(e)) { + return new (S.Context) MSPropertySubscriptExpr( + rebuild(PSE->getBase()), PSE->getIdx(), PSE->getType(), + PSE->getValueKind(), PSE->getObjectKind(), PSE->getRBracketLoc()); + } + llvm_unreachable("bad expression to rebuild!"); } }; @@ -329,11 +335,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; @@ -1400,6 +1414,18 @@ // MSVC __declspec(property) references //===----------------------------------------------------------------------===// +MSPropertyRefExpr * +MSPropertyOpBuilder::getBaseMSProperty(MSPropertySubscriptExpr *E) { + Expr *Base = E->getBase(); + CallArgs.insert(CallArgs.begin(), E->getIdx()); + while (auto *MSPropSubscript = + dyn_cast(Base->IgnoreParens())) { + CallArgs.insert(CallArgs.begin(), MSPropSubscript->getIdx()); + Base = MSPropSubscript->getBase(); + } + return cast(Base->IgnoreParens()); +} + Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { InstanceBase = capture(RefExpr->getBaseExpr()); @@ -1432,9 +1458,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 +1487,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 +1514,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 +1544,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 +1579,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!"); } @@ -1576,6 +1614,16 @@ = dyn_cast(opaqueRef)) { OpaqueValueExpr *baseOVE = cast(refExpr->getBaseExpr()); return MSPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); + } else if (MSPropertySubscriptExpr *RefExpr + = dyn_cast(opaqueRef)) { + Expr *Base = RefExpr->getBase(); + while (auto *MSPropSubscript = + dyn_cast(Base->IgnoreParens())) { + Base = MSPropSubscript->getBase(); + } + OpaqueValueExpr *BaseOVE = cast( + cast(Base->IgnoreParens())->getBaseExpr()); + return MSPropertyRefRebuilder(S, BaseOVE->getSourceExpr()).rebuild(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -6818,6 +6818,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: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1641,6 +1641,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)); @@ -3037,6 +3044,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: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -1668,6 +1668,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: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -754,6 +754,7 @@ case Stmt::CXXUuidofExprClass: case Stmt::CXXFoldExprClass: case Stmt::MSPropertyRefExprClass: + case Stmt::MSPropertySubscriptExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::ArrayTypeTraitExprClass: Index: test/CodeGenCXX/ms-property.cpp =================================================================== --- test/CodeGenCXX/ms-property.cpp +++ 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,89 @@ 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]; +} + // 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: [[GET:%.+]] = call float @"\01?GetX@?$St@M@@QEAAMMM@Z"(%class.St* %{{.+}} float 2.300000e+01, float 1.000000e+00) + // CHECK-NEXT: [[INC:%.+]] = fadd float [[GET]], 1.000000e+00 + // CHECK-NEXT: call void @"\01?PutX@?$St@M@@QEAAXMMM@Z"(%class.St* %{{.+}}, float 2.300000e+01, float 1.000000e+00, float [[INC]]) + ++p2->x[23][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: [[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: [[T_X:%.+]] = call i32 @"\01?get_x@Test1@@QEBAHXZ"(%class.Test1* %{{.+}}) + // 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: test/SemaCXX/ms-property-error.cpp =================================================================== --- test/SemaCXX/ms-property-error.cpp +++ 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: test/SemaCXX/ms-property.cpp =================================================================== --- test/SemaCXX/ms-property.cpp +++ 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: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -325,6 +325,7 @@ K = CXCursor_UnaryExpr; break; + case Stmt::MSPropertySubscriptExprClass: case Stmt::ArraySubscriptExprClass: K = CXCursor_ArraySubscriptExpr; break;