r254067 - [MSVC] 'property' with an empty array in array subscript expression.

Alexey Bataev via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 25 04:01:07 PST 2015


Author: abataev
Date: Wed Nov 25 06:01:00 2015
New Revision: 254067

URL: http://llvm.org/viewvc/llvm-project?rev=254067&view=rev
Log:
[MSVC] 'property' with an empty array in array 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:
```
__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);
Differential Revision: http://reviews.llvm.org/D13336

Added:
    cfe/trunk/test/SemaCXX/ms-property-error.cpp   (with props)
    cfe/trunk/test/SemaCXX/ms-property.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/Basic/StmtNodes.td
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaPseudoObject.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/CodeGenCXX/ms-property.cpp
    cfe/trunk/tools/libclang/CXCursor.cpp

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Nov 25 06:01:00 2015
@@ -677,6 +677,69 @@ public:
   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<Expr>(SubExprs[BASE_EXPR]); }
+  const Expr *getBase() const { return cast<Expr>(SubExprs[BASE_EXPR]); }
+
+  Expr *getIdx() { return cast<Expr>(SubExprs[IDX_EXPR]); }
+  const Expr *getIdx() const { return cast<Expr>(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.
 ///

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed Nov 25 06:01:00 2015
@@ -2112,6 +2112,8 @@ DEF_TRAVERSE_STMT(MSPropertyRefExpr, {
   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.

Modified: cfe/trunk/include/clang/Basic/StmtNodes.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/StmtNodes.td (original)
+++ cfe/trunk/include/clang/Basic/StmtNodes.td Wed Nov 25 06:01:00 2015
@@ -180,6 +180,7 @@ def TypoExpr : DStmt<Expr>;
 
 // Microsoft Extensions.
 def MSPropertyRefExpr : DStmt<Expr>;
+def MSPropertySubscriptExpr : DStmt<Expr>;
 def CXXUuidofExpr : DStmt<Expr>; 
 def SEHTryStmt : Stmt;
 def SEHExceptStmt : Stmt;

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed Nov 25 06:01:00 2015
@@ -1413,6 +1413,7 @@ namespace clang {
 
       // 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

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Nov 25 06:01:00 2015
@@ -3004,6 +3004,7 @@ bool Expr::HasSideEffects(const ASTConte
     return true;
 
   case MSPropertyRefExprClass:
+  case MSPropertySubscriptExprClass:
   case CompoundAssignOperatorClass:
   case VAArgExprClass:
   case AtomicExprClass:

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Wed Nov 25 06:01:00 2015
@@ -136,6 +136,7 @@ static Cl::Kinds ClassifyInternal(ASTCon
   case Expr::ObjCIvarRefExprClass:
   case Expr::FunctionParmPackExprClass:
   case Expr::MSPropertyRefExprClass:
+  case Expr::MSPropertySubscriptExprClass:
   case Expr::OMPArraySectionExprClass:
     return Cl::CL_LValue;
 

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Nov 25 06:01:00 2015
@@ -8974,6 +8974,7 @@ static ICEDiag CheckICE(const Expr* E, c
   case Expr::CXXTypeidExprClass:
   case Expr::CXXUuidofExprClass:
   case Expr::MSPropertyRefExprClass:
+  case Expr::MSPropertySubscriptExprClass:
   case Expr::CXXNullPtrLiteralExprClass:
   case Expr::UserDefinedLiteralClass:
   case Expr::CXXThisExprClass:

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Nov 25 06:01:00 2015
@@ -2811,6 +2811,7 @@ recurse:
   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");

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Nov 25 06:01:00 2015
@@ -1738,6 +1738,13 @@ void StmtPrinter::VisitMSPropertyRefExpr
   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:

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Wed Nov 25 06:01:00 2015
@@ -1129,6 +1129,11 @@ void StmtProfiler::VisitMSPropertyRefExp
   VisitDecl(S->getPropertyDecl());
 }
 
+void StmtProfiler::VisitMSPropertySubscriptExpr(
+    const MSPropertySubscriptExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) {
   VisitExpr(S);
   ID.AddBoolean(S->isImplicit());

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Wed Nov 25 06:01:00 2015
@@ -1179,6 +1179,7 @@ CanThrowResult Sema::canThrow(const Expr
     return CT_Cannot;
 
   case Expr::MSPropertyRefExprClass:
+  case Expr::MSPropertySubscriptExprClass:
     llvm_unreachable("Invalid class for expression");
 
 #define STMT(CLASS, PARENT) case Expr::CLASS##Class:

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov 25 06:01:00 2015
@@ -3901,6 +3901,13 @@ static bool checkArithmeticOnObjCPointer
   return true;
 }
 
+static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) {
+  auto *BaseNoParens = Base->IgnoreParens();
+  if (auto *MSProp = dyn_cast<MSPropertyRefExpr>(BaseNoParens))
+    return MSProp->getPropertyDecl()->getType()->isArrayType();
+  return isa<MSPropertySubscriptExpr>(BaseNoParens);
+}
+
 ExprResult
 Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
                               Expr *idx, SourceLocation rbLoc) {
@@ -3921,10 +3928,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S,
   // 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S,
                                             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

Modified: cfe/trunk/lib/Sema/SemaPseudoObject.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaPseudoObject.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaPseudoObject.cpp (original)
+++ cfe/trunk/lib/Sema/SemaPseudoObject.cpp Wed Nov 25 06:01:00 2015
@@ -44,17 +44,76 @@ using namespace sema;
 
 namespace {
   // Basically just a very focused copy of TreeTransform.
-  template <class T> struct Rebuilder {
+  struct Rebuilder {
     Sema &S;
-    Rebuilder(Sema &S) : S(S) {}
+    unsigned MSPropertySubscriptCount;
+    typedef llvm::function_ref<Expr *(Expr *, unsigned)> SpecificRebuilderRefTy;
+    const SpecificRebuilderRefTy &SpecificCallback;
+    Rebuilder(Sema &S, const SpecificRebuilderRefTy &SpecificCallback)
+        : S(S), MSPropertySubscriptCount(0),
+          SpecificCallback(SpecificCallback) {}
 
-    T &getDerived() { return static_cast<T&>(*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<typename T::specific_type>(e))
-        return getDerived().rebuildSpecific(specific);
+      if (auto *PRE = dyn_cast<ObjCPropertyRefExpr>(e))
+        return rebuildObjCPropertyRefExpr(PRE);
+      if (auto *SRE = dyn_cast<ObjCSubscriptRefExpr>(e))
+        return rebuildObjCSubscriptRefExpr(SRE);
+      if (auto *MSPRE = dyn_cast<MSPropertyRefExpr>(e))
+        return rebuildMSPropertyRefExpr(MSPRE);
+      if (auto *MSPSE = dyn_cast<MSPropertySubscriptExpr>(e))
+        return rebuildMSPropertySubscriptExpr(MSPSE);
 
       // Otherwise, we should look through and rebuild anything that
       // IgnoreParens would.
@@ -125,72 +184,6 @@ namespace {
     }
   };
 
-  struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> {
-    Expr *NewBase;
-    ObjCPropertyRefRebuilder(Sema &S, Expr *newBase)
-      : Rebuilder<ObjCPropertyRefRebuilder>(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<ObjCSubscriptRefRebuilder> {
-    Expr *NewBase;
-    Expr *NewKeyExpr;
-    ObjCSubscriptRefRebuilder(Sema &S, Expr *newBase, Expr *newKeyExpr)
-    : Rebuilder<ObjCSubscriptRefRebuilder>(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<MSPropertyRefRebuilder> {
-    Expr *NewBase;
-    MSPropertyRefRebuilder(Sema &S, Expr *newBase)
-    : Rebuilder<MSPropertyRefRebuilder>(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 @@ namespace {
  class MSPropertyOpBuilder : public PseudoOpBuilder {
    MSPropertyRefExpr *RefExpr;
    OpaqueValueExpr *InstanceBase;
+   SmallVector<Expr *, 4> 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 @@ Expr *ObjCPropertyOpBuilder::rebuildAndC
   // 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 @@ Expr *ObjCSubscriptOpBuilder::rebuildAnd
   // 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 @@ ExprResult ObjCSubscriptOpBuilder::build
 //  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<MSPropertySubscriptExpr>(Base)) {
+    CallArgs.insert(CallArgs.begin(), MSPropSubscript->getIdx());
+    Base = MSPropSubscript->getBase()->IgnoreParens();
+  }
+  return cast<MSPropertyRefExpr>(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 @@ ExprResult MSPropertyOpBuilder::buildGet
     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 @@ ExprResult MSPropertyOpBuilder::buildSet
     return ExprError();
   }
 
-  SmallVector<Expr*, 1> ArgExprs;
+  SmallVector<Expr*, 4> 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 @@ ExprResult Sema::checkPseudoObjectRValue
              = dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
     MSPropertyOpBuilder builder(*this, refExpr);
     return builder.buildRValueOperation(E);
+  } else if (MSPropertySubscriptExpr *RefExpr =
+                 dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
+    MSPropertyOpBuilder Builder(*this, RefExpr);
+    return Builder.buildRValueOperation(E);
   } else {
     llvm_unreachable("unknown pseudo-object kind!");
   }
@@ -1514,6 +1546,10 @@ ExprResult Sema::checkPseudoObjectIncDec
              = dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
     MSPropertyOpBuilder builder(*this, refExpr);
     return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
+  } else if (MSPropertySubscriptExpr *RefExpr
+             = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) {
+    MSPropertyOpBuilder Builder(*this, RefExpr);
+    return Builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
   } else {
     llvm_unreachable("unknown pseudo-object kind!");
   }
@@ -1545,8 +1581,12 @@ ExprResult Sema::checkPseudoObjectAssign
     return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
   } else if (MSPropertyRefExpr *refExpr
              = dyn_cast<MSPropertyRefExpr>(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<MSPropertySubscriptExpr>(opaqueRef)) {
+      MSPropertyOpBuilder Builder(*this, RefExpr);
+      return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
   } else {
     llvm_unreachable("unknown pseudo-object kind!");
   }
@@ -1556,29 +1596,11 @@ ExprResult Sema::checkPseudoObjectAssign
 /// 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<ObjCPropertyRefExpr>(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<OpaqueValueExpr>(refExpr->getBase());
-    return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E);
-  } else if (ObjCSubscriptRefExpr *refExpr
-               = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) {
-    OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr());
-    OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr());
-    return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(), 
-                                     keyOVE->getSourceExpr()).rebuild(E);
-  } else if (MSPropertyRefExpr *refExpr
-             = dyn_cast<MSPropertyRefExpr>(opaqueRef)) {
-    OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(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<OpaqueValueExpr>(E)->getSourceExpr();
+                   })
+      .rebuild(E);
 }
 
 /// Given a pseudo-object expression, recreate what it looks like

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Nov 25 06:01:00 2015
@@ -6919,6 +6919,25 @@ TreeTransform<Derived>::TransformMSPrope
 }
 
 template <typename Derived>
+ExprResult TreeTransform<Derived>::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 <typename Derived>
 StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
   StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock());
   if (TryBlock.isInvalid())

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Nov 25 06:01:00 2015
@@ -1662,6 +1662,13 @@ void ASTStmtReader::VisitMSPropertyRefEx
   E->TheDecl = ReadDeclAs<MSPropertyDecl>(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 @@ Stmt *ASTReader::ReadStmtFromStream(Modu
     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;

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Nov 25 06:01:00 2015
@@ -1689,6 +1689,14 @@ void ASTStmtWriter::VisitMSPropertyRefEx
   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);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Wed Nov 25 06:01:00 2015
@@ -755,6 +755,7 @@ void ExprEngine::Visit(const Stmt *S, Ex
     case Stmt::CXXUuidofExprClass:
     case Stmt::CXXFoldExprClass:
     case Stmt::MSPropertyRefExprClass:
+    case Stmt::MSPropertySubscriptExprClass:
     case Stmt::CXXUnresolvedConstructExprClass:
     case Stmt::DependentScopeDeclRefExprClass:
     case Stmt::ArrayTypeTraitExprClass:

Modified: cfe/trunk/test/CodeGenCXX/ms-property.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/ms-property.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/ms-property.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/ms-property.cpp Wed Nov 25 06:01:00 2015
@@ -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 @@ public:
   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 <typename T>
+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 <typename T>
+void foo(T i, T j) {
+  St<T> 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<float> *p2 = 0;
+  // CHECK: call i32 @"\01?GetX at S@@QEAAHHH at Z"(%class.S* %{{.+}}, i32 223, i32 11)
+  int j = p1->x[223][11];
+  // CHECK: [[J:%.+]] = load i32, i32* %
+  // CHECK-NEXT: call void @"\01?PutX at S@@QEAAXHHH at Z"(%class.S* %{{.+}}, i32 23, i32 1, i32 [[J]])
+  p1->x[23][1] = j;
+  // CHECK: call float @"\01?GetX@?$St at M@@QEAAMMM at 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 at M@@QEAAXMMM at 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 at M@@QEAAMMM at 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 at M@@QEAAXMMM at Z"(%class.St* %{{.+}}, float [[CONV]], float 1.000000e+00, float [[INC]])
+  ++p2->x[idx()][1];
+  // CHECK: call void @"\01??$foo at H@@YAXHH at Z"(i32 %{{.+}}, i32 %{{.+}})
+  foo(argc, (int)argv[0][0]);
+  // CHECK: [[P2:%.+]] = load %class.St*, %class.St** %
+  // CHECK: [[T_X:%.+]] = call i32 @"\01?get_x at Test1@@QEBAHXZ"(%class.Test1* %{{.+}})
+  // CHECK: [[P1:%.+]] = load %class.S*, %class.S** %
+  // CHECK: [[P1_X_22_33:%.+]] = call i32 @"\01?GetX at S@@QEAAHHH at 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 at M@@QEAAXDHN at 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 at S@@QEAAHHH at 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 at 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 at M@@QEAAXMMM at 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 at Test1@@SAPEAV1 at XZ"()
   // CHECK-NEXT: call i32 @"\01?get_x at Test1@@QEBAHXZ"(%class.Test1* [[CALL]])
   return Test1::GetTest1()->X;
 }
+
+// CHECK: define linkonce_odr void @"\01??$foo at H@@YAXHH at Z"(i32 %{{.+}}, i32 %{{.+}})
+// CHECK: call i32 @"\01?GetX@?$St at H@@QEAAHHH at Z"(%class.St{{.+}}* [[BAR:%.+]], i32 %{{.+}} i32 %{{.+}})
+// CHECK: call void @"\01?PutX@?$St at H@@QEAAXHHH at Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}}, i32 %{{.+}}, i32 %{{.+}})
+// CHECK: call i32 @"\01?GetX@?$St at H@@QEAAHHH at Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}} i32 %{{.+}})
+// CHECK: call void @"\01?PutY@?$St at H@@QEAAXDHN at Z"(%class.St{{.+}}* [[BAR]], i8 %{{.+}}, i32 %{{.+}}, double %{{.+}}
+// CHECK: call i32 @"\01?GetX@?$St at H@@QEAAHHH at Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}} i32 %{{.+}})
+// CHECK: call i8 @"\01?GetY@?$St at H@@QEAADDVTest1@@@Z"(%class.St{{.+}}* [[BAR]], i8 %{{.+}}, %class.Test1* %{{.+}})
+// CHECK: call void @"\01?PutX@?$St at H@@QEAAXHHH at Z"(%class.St{{.+}}* [[BAR]], i32 %{{.+}}, i32 %{{.+}}, i32 %{{.+}})
+#endif //HEADER

Added: cfe/trunk/test/SemaCXX/ms-property-error.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ms-property-error.cpp?rev=254067&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/ms-property-error.cpp (added)
+++ cfe/trunk/test/SemaCXX/ms-property-error.cpp Wed Nov 25 06:01:00 2015
@@ -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 <typename T>
+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<float> *p2 = 0;
+  St<int> a; // expected-note {{in instantiation of member function 'St<int>::~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}}
+}

Propchange: cfe/trunk/test/SemaCXX/ms-property-error.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/ms-property-error.cpp
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Propchange: cfe/trunk/test/SemaCXX/ms-property-error.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaCXX/ms-property.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ms-property.cpp?rev=254067&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/ms-property.cpp (added)
+++ cfe/trunk/test/SemaCXX/ms-property.cpp Wed Nov 25 06:01:00 2015
@@ -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 <typename T>
+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<float> *p2 = 0;
+  // CHECK: St<int> a;
+  St<int> 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

Propchange: cfe/trunk/test/SemaCXX/ms-property.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/ms-property.cpp
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Propchange: cfe/trunk/test/SemaCXX/ms-property.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=254067&r1=254066&r2=254067&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Wed Nov 25 06:01:00 2015
@@ -329,6 +329,7 @@ CXCursor cxcursor::MakeCXCursor(const St
     K = CXCursor_UnaryExpr;
     break;
 
+  case Stmt::MSPropertySubscriptExprClass:
   case Stmt::ArraySubscriptExprClass:
     K = CXCursor_ArraySubscriptExpr;
     break;




More information about the cfe-commits mailing list