Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -463,6 +463,10 @@ typedef llvm::SmallVector DeleteLocs; llvm::MapVector DeleteExprs; + /// \brief Map of additional arguments for ms property calls. + typedef llvm::SmallVector MSPropArgsTy; + llvm::DenseMap MSPropArgsMap; + typedef llvm::SmallPtrSet RecordDeclSetTy; /// PureVirtualClassDiagSet - a set of class declarations which we have Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3958,7 +3958,21 @@ // 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()) { + // 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); + auto *MSProp = dyn_cast(base->IgnoreParens()); + if (MSProp && MSProp->getPropertyDecl()->getType()->isArrayType()) { + auto I = MSPropArgsMap.find(MSProp); + if (I == MSPropArgsMap.end()) + I = MSPropArgsMap.insert(std::make_pair(MSProp, MSPropArgsTy())).first; + I->second.push_back(idx); + } else if (base->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(base); if (result.isInvalid()) return ExprError(); base = result.get(); @@ -3969,6 +3983,9 @@ idx = result.get(); } + if (MSProp && MSProp->getPropertyDecl()->getType()->isArrayType()) + return base; + // Build an unanalyzed expression if either operand is type-dependent. if (getLangOpts().CPlusPlus && (base->isTypeDependent() || idx->isTypeDependent())) { Index: lib/Sema/SemaPseudoObject.cpp =================================================================== --- lib/Sema/SemaPseudoObject.cpp +++ lib/Sema/SemaPseudoObject.cpp @@ -1432,6 +1432,11 @@ } MultiExprArg ArgExprs; + auto I = S.MSPropArgsMap.find(RefExpr); + if (I != S.MSPropArgsMap.end()) { + ArgExprs = I->second; + S.MSPropArgsMap.erase(I); + } return S.ActOnCallExpr(S.getCurScope(), GetterExpr.get(), RefExpr->getSourceRange().getBegin(), ArgExprs, RefExpr->getSourceRange().getEnd()); @@ -1461,7 +1466,12 @@ return ExprError(); } - SmallVector ArgExprs; + Sema::MSPropArgsTy ArgExprs; + auto I = S.MSPropArgsMap.find(RefExpr); + if (I != S.MSPropArgsMap.end()) { + ArgExprs = I->second; + S.MSPropArgsMap.erase(I); + } ArgExprs.push_back(op); return S.ActOnCallExpr(S.getCurScope(), SetterExpr.get(), RefExpr->getSourceRange().getBegin(), ArgExprs, Index: test/CodeGenCXX/ms-property.cpp =================================================================== --- test/CodeGenCXX/ms-property.cpp +++ test/CodeGenCXX/ms-property.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s + +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; } +}; + +// CHECK-LABEL: main +int main() +{ + 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; + return 0; +} +