diff options
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 55 | ||||
-rw-r--r-- | clang/test/SemaCXX/overloaded-operator.cpp | 25 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/properties.mm | 35 |
3 files changed, 99 insertions, 16 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 65bdd2a47fb..7dd17a028f6 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3341,33 +3341,56 @@ static bool checkArithmeticOnObjCPointer(Sema &S, } 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 diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index 8ecb54dde6d..e5b3fab33c8 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -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>]; + } +} diff --git a/clang/test/SemaObjCXX/properties.mm b/clang/test/SemaObjCXX/properties.mm index 804d6829b16..abd4db998bc 100644 --- a/clang/test/SemaObjCXX/properties.mm +++ b/clang/test/SemaObjCXX/properties.mm @@ -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]; } + }; +} +@interface Test9 +@property test9::CString name; +@end +namespace test9 { + char test(Test9 *t) { + return t.name[0]; + } +} + +namespace test10 { + struct A { operator const char*(); }; + struct B { operator const char*(); }; +} +@interface Test10 +@property test10::A a; +@property test10::B b; +@property int index; +@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]; + } +} |