]> granicus.if.org Git - clang/commitdiff
Support overloading of the subscript operator[], including support for
authorDouglas Gregor <dgregor@apple.com>
Wed, 19 Nov 2008 17:17:41 +0000 (17:17 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 19 Nov 2008 17:17:41 +0000 (17:17 +0000)
built-in operator candidates. Test overloading of '&' and ','.

In C++, a comma expression is an lvalue if its right-hand
subexpression is an lvalue. Update Expr::isLvalue accordingly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59643 91177308-0d34-0410-b5e6-96231b3b80d8

Driver/PrintParserCallbacks.cpp
include/clang/Parse/Action.h
lib/AST/Expr.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
test/SemaCXX/overloaded-builtin-operators.cpp
test/SemaCXX/overloaded-operator.cpp
www/cxx_status.html

index 2a85f64646faa4c56b0ed3cdf7178cc221937f92..2ee113fcda53612cc3b1395b977e86e47ad1b13e 100644 (file)
@@ -441,8 +441,9 @@ namespace {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
     }
-    virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
-                                               ExprTy *Idx, SourceLocation RLoc) {
+    virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, 
+                                               SourceLocation LLoc, ExprTy *Idx,
+                                               SourceLocation RLoc) {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
     }
index 71785430035996ef94ba4af5a8d8f92f78e8168d..d662529217061a8c861785e9371711c7f4af7f99 100644 (file)
@@ -513,7 +513,8 @@ public:
                                          tok::TokenKind Kind, ExprTy *Input) {
     return 0;
   }
-  virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+  virtual ExprResult ActOnArraySubscriptExpr(Scope *S,
+                                             ExprTy *Base, SourceLocation LLoc,
                                              ExprTy *Idx, SourceLocation RLoc) {
     return 0;
   }
index a179af8b1450347f9ac95b0ef627b8d30b00c8cc..061402076e53b4a0969be1bc62ae809134da2365 100644 (file)
@@ -412,6 +412,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
   case BinaryOperatorClass:
   case CompoundAssignOperatorClass: {
     const BinaryOperator *BinOp = cast<BinaryOperator>(this);
+
+    if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.comma]p1
+        BinOp->getOpcode() == BinaryOperator::Comma)
+      return BinOp->getRHS()->isLvalue(Ctx);
+
     if (!BinOp->isAssignmentOp())
       return LV_InvalidExpression;
 
index 5f36f0bb272cf0f4ce0cecb87931d356719e2ed1..74b0715de2acbe196071fea0ac8a731a56425b59 100644 (file)
@@ -672,7 +672,8 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       SourceLocation RLoc = Tok.getLocation();
       
       if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square))
-        LHS = Actions.ActOnArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc);
+        LHS = Actions.ActOnArraySubscriptExpr(CurScope, LHS.Val, Loc, 
+                                              Idx.Val, RLoc);
       else 
         LHS = ExprResult(true);
 
index b10a98f0b3cfe428e7a1bf0137ac58d49f21c101..983fa306d2bcc564b912adea90c6860ff6e231a9 100644 (file)
@@ -652,8 +652,9 @@ public:
   virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, 
                                          tok::TokenKind Kind, ExprTy *Input);
   
-  virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
-                                             ExprTy *Idx, SourceLocation RLoc);
+  virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, 
+                                             SourceLocation LLoc, ExprTy *Idx,
+                                             SourceLocation RLoc);
   virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
                                               tok::TokenKind OpKind,
                                               SourceLocation MemberLoc,
index c7803722fe9f2dfa42c41fb022268f31dfdb7af9..a780012235a309efc6de40f5ef6a410dbcdf4bcb 100644 (file)
@@ -861,10 +861,93 @@ Action::ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
 }
 
 Action::ExprResult Sema::
-ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, SourceLocation LLoc,
                         ExprTy *Idx, SourceLocation RLoc) {
   Expr *LHSExp = static_cast<Expr*>(Base), *RHSExp = static_cast<Expr*>(Idx);
 
+  if (getLangOptions().CPlusPlus &&
+      LHSExp->getType()->isRecordType() || 
+      LHSExp->getType()->isEnumeralType() ||
+      RHSExp->getType()->isRecordType() ||
+      RHSExp->getType()->isRecordType()) {
+    // Add the appropriate overloaded operators (C++ [over.match.oper]) 
+    // to the candidate set.
+    OverloadCandidateSet CandidateSet;
+    Expr *Args[2] = { LHSExp, RHSExp };
+    AddOperatorCandidates(OO_Subscript, S, Args, 2, CandidateSet);
+    
+    // Perform overload resolution.
+    OverloadCandidateSet::iterator Best;
+    switch (BestViableFunction(CandidateSet, Best)) {
+    case OR_Success: {
+      // We found a built-in operator or an overloaded operator.
+      FunctionDecl *FnDecl = Best->Function;
+
+      if (FnDecl) {
+        // We matched an overloaded operator. Build a call to that
+        // operator.
+
+        // Convert the arguments.
+        if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+          if (PerformObjectArgumentInitialization(LHSExp, Method) ||
+              PerformCopyInitialization(RHSExp, 
+                                        FnDecl->getParamDecl(0)->getType(),
+                                        "passing"))
+            return true;
+        } else {
+          // Convert the arguments.
+          if (PerformCopyInitialization(LHSExp,
+                                        FnDecl->getParamDecl(0)->getType(),
+                                        "passing") ||
+              PerformCopyInitialization(RHSExp,
+                                        FnDecl->getParamDecl(1)->getType(),
+                                        "passing"))
+            return true;
+        }
+
+        // Determine the result type
+        QualType ResultTy 
+          = FnDecl->getType()->getAsFunctionType()->getResultType();
+        ResultTy = ResultTy.getNonReferenceType();
+        
+        // Build the actual expression node.
+        Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(), 
+                                       SourceLocation());
+        UsualUnaryConversions(FnExpr);
+
+        return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, LLoc);
+      } else {
+        // We matched a built-in operator. Convert the arguments, then
+        // break out so that we will build the appropriate built-in
+        // operator node.
+        if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0],
+                                      "passing") ||
+            PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1],
+                                      "passing"))
+          return true;
+
+        break;
+      }
+    }
+
+    case OR_No_Viable_Function:
+      // No viable function; fall through to handling this as a
+      // built-in operator, which will produce an error message for us.
+      break;
+
+    case OR_Ambiguous:
+      Diag(LLoc,  diag::err_ovl_ambiguous_oper)
+          << "[]"
+          << LHSExp->getSourceRange() << RHSExp->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return true;
+    }
+
+    // Either we found no viable overloaded operator or we matched a
+    // built-in operator. In either case, fall through to trying to
+    // build a built-in operation.
+  }
+
   // Perform default conversions.
   DefaultFunctionArrayConversion(LHSExp);
   DefaultFunctionArrayConversion(RHSExp);
@@ -3009,7 +3092,6 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
     // built-in operator. In either case, fall through to trying to
     // build a built-in operation.
   } 
-
   
   // Build a built-in binary operation.
   return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
index 29d721c45bbf059bdb504c81f67754e3d530f704..41509f96e77693300cba4e7eba84a307e329007f 100644 (file)
@@ -113,5 +113,9 @@ void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr,
   int volatile *vip2 = +vip;
   int i1 = +sr;
   int i2 = -sr;
+
+  // C++ [over.built]p13:
+  int volatile &ivr2 = vip[17];
+  int const &icr2 = 17[cip];
 }
 
index 29486568185dd6f344d803b16710f42f1515e9ff..1eb86bd1aa002147746a4fe6d347b8e813c6fe7f 100644 (file)
@@ -97,3 +97,27 @@ void test_smartptr(SmartPtr ptr, const SmartPtr cptr) {
   int &ir = *ptr;
   // FIXME: reinstate long &lr = *cptr;
 }
+
+
+struct ArrayLike {
+  int& operator[](int);
+};
+
+void test_arraylike(ArrayLike a) {
+  int& ir = a[17];
+}
+
+struct SmartRef {
+  int* operator&();
+};
+
+void test_smartref(SmartRef r) {
+  int* ip = &r;
+}
+
+bool& operator,(X, Y);
+
+void test_comma(X x, Y y) {
+  bool& b1 = (x, y);
+  X& xr = (x, x);
+}
index 7c51fb387d0578a0b91e0eac18dc43f3de519d60..6db2840b7af8f8d5d9ed34d20392dc16c1dda486 100644 (file)
@@ -981,7 +981,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.5 [over.sub]</td>\r
   <td class="na" align="center">N/A</td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="basic" align="center"></td>\r
+  <td class="advanced" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r