r176428 - Perform non-overload placeholder conversions on the operands

John McCall rjmccall at apple.com
Sun Mar 3 17:30:56 PST 2013


Author: rjmccall
Date: Sun Mar  3 19:30:55 2013
New Revision: 176428

URL: http://llvm.org/viewvc/llvm-project?rev=176428&view=rev
Log:
Perform non-overload placeholder conversions on the operands
to a subscript operator.

rdar://13332183

Modified:
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp
    cfe/trunk/test/SemaObjCXX/properties.mm

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=176428&r1=176427&r2=176428&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Mar  3 19:30:55 2013
@@ -3341,33 +3341,56 @@ static bool checkArithmeticOnObjCPointer
 }
 
 ExprResult
-Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
-                              Expr *Idx, SourceLocation RLoc) {
+Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
+                              Expr *idx, SourceLocation rbLoc) {
   // Since this might be a postfix expression, get rid of ParenListExprs.
-  ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
-  if (Result.isInvalid()) return ExprError();
-  Base = Result.take();
+  if (isa<ParenListExpr>(base)) {
+    ExprResult result = MaybeConvertParenListExprToParenExpr(S, base);
+    if (result.isInvalid()) return ExprError();
+    base = result.take();
+  }
 
-  Expr *LHSExp = Base, *RHSExp = Idx;
+  // Handle any non-overload placeholder types in the base and index
+  // expressions.  We can't handle overloads here because the other
+  // 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()) {
+    ExprResult result = CheckPlaceholderExpr(base);
+    if (result.isInvalid()) return ExprError();
+    base = result.take();
+  }
+  if (idx->getType()->isNonOverloadPlaceholderType()) {
+    ExprResult result = CheckPlaceholderExpr(idx);
+    if (result.isInvalid()) return ExprError();
+    idx = result.take();
+  }
 
+  // Build an unanalyzed expression if either operand is type-dependent.
   if (getLangOpts().CPlusPlus &&
-      (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
-    return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
+      (base->isTypeDependent() || idx->isTypeDependent())) {
+    return Owned(new (Context) ArraySubscriptExpr(base, idx,
                                                   Context.DependentTy,
                                                   VK_LValue, OK_Ordinary,
-                                                  RLoc));
+                                                  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
+  // operators, so there's nothing interesting for overload resolution
+  // to do if there aren't any record types involved.
+  //
+  // ObjC pointers have their own subscripting logic that is not tied
+  // to overload resolution and so should not take this path.
   if (getLangOpts().CPlusPlus &&
-      (LHSExp->getType()->isRecordType() ||
-       LHSExp->getType()->isEnumeralType() ||
-       RHSExp->getType()->isRecordType() ||
-       RHSExp->getType()->isEnumeralType()) &&
-      !LHSExp->getType()->isObjCObjectPointerType()) {
-    return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, Base, Idx);
+      (base->getType()->isRecordType() ||
+       (!base->getType()->isObjCObjectPointerType() &&
+        idx->getType()->isRecordType()))) {
+    return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx);
   }
 
-  return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc);
+  return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
 }
 
 ExprResult

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=176428&r1=176427&r2=176428&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Sun Mar  3 19:30:55 2013
@@ -415,3 +415,28 @@ namespace PR11784 {
   void f(int);
   void g() { A x; x = f; }
 }
+
+namespace test10 {
+  struct A {
+    void operator[](float (*fn)(int)); // expected-note 2 {{not viable: no overload of 'bar' matching 'float (*)(int)'}}
+  };
+
+  float foo(int);
+  float foo(float);
+
+  template <class T> T bar(T);
+  template <class T, class U> T bar(U);
+
+  void test(A &a) {
+    a[&foo];
+    a[foo];
+
+    a[&bar<int>]; // expected-error {{no viable overloaded operator[]}}
+    a[bar<int>]; // expected-error {{no viable overloaded operator[]}}
+
+    // If these fail, it's because we're not letting the overload
+    // resolution for operator| resolve the overload of 'bar'.
+    a[&bar<float>];
+    a[bar<float>];
+  }
+}

Modified: cfe/trunk/test/SemaObjCXX/properties.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/properties.mm?rev=176428&r1=176427&r2=176428&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/properties.mm (original)
+++ cfe/trunk/test/SemaObjCXX/properties.mm Sun Mar  3 19:30:55 2013
@@ -129,3 +129,38 @@ extern void* VoidType;
 extern decltype(TestNonTrivialObj.p1 = NonTrivial1())* VoidType;
 extern decltype(TestNonTrivialObj.p2 = NonTrivial2())* VoidType;
 
+// rdar://13332183
+namespace test9 {
+  struct CString {
+    const char *_data;
+    char operator[](int i) const { return _data[i]; }
+  };
+}
+ at interface Test9
+ at property test9::CString name;
+ at end
+namespace test9 {
+  char test(Test9 *t) {
+    return t.name[0];
+  }
+}
+
+namespace test10 {
+  struct A { operator const char*(); };
+  struct B { operator const char*(); };
+}
+ at interface Test10
+ at property test10::A a;
+ at property test10::B b;
+ at property int index;
+ at end
+namespace test10 {
+  void test(Test10 *t) {
+    (void) t.a[6];
+    (void) 6[t.b];
+    (void) "help"[t.index];
+    (void) t.index["help"];
+    (void) t.a[t.index];
+    (void) t.index[t.b];
+  }
+}





More information about the cfe-commits mailing list