summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Sema/Sema.h5
-rw-r--r--clang/lib/Sema/SemaOverload.cpp16
-rw-r--r--clang/lib/Sema/TreeTransform.h14
-rw-r--r--clang/test/SemaCXX/overloaded-operator.cpp35
4 files changed, 57 insertions, 13 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 80b6978b925..b33f63225cb 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2914,12 +2914,13 @@ public:
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *input);
+ Expr *input, bool RequiresADL = true);
ExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS);
+ Expr *LHS, Expr *RHS,
+ bool RequiresADL = true);
ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
SourceLocation RLoc,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 66b252e1446..0e53ffa83fe 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -11927,7 +11927,7 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
ExprResult
Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *Input) {
+ Expr *Input, bool PerformADL) {
OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -11978,9 +11978,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
- /*ExplicitTemplateArgs*/nullptr,
- CandidateSet);
+ if (PerformADL) {
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+ /*ExplicitTemplateArgs*/nullptr,
+ CandidateSet);
+ }
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -12118,7 +12120,7 @@ ExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS) {
+ Expr *LHS, Expr *RHS, bool PerformADL) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
@@ -12149,7 +12151,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, NamingClass,
NestedNameSpecifierLoc(), OpNameInfo,
- /*ADL*/ true, IsOverloaded(Fns),
+ /*ADL*/PerformADL, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return new (Context)
CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
@@ -12192,7 +12194,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
// performed for an assignment operator (nor for operator[] nor operator->,
// which don't get here).
- if (Opc != BO_Assign)
+ if (Opc != BO_Assign && PerformADL)
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ nullptr,
CandidateSet);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a9ecf721db4..fa582c22135 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12636,10 +12636,14 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Compute the transformed set of functions (and function templates) to be
// used during overload resolution.
UnresolvedSet<16> Functions;
+ bool RequiresADL;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
- assert(ULE->requiresADL());
Functions.append(ULE->decls_begin(), ULE->decls_end());
+ // If the overload could not be resolved in the template definition
+ // (because we had a dependent argument), ADL is performed as part of
+ // template instantiation.
+ RequiresADL = ULE->requiresADL();
} else {
// If we've resolved this to a particular non-member function, just call
// that function. If we resolved it to a member function,
@@ -12647,6 +12651,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl();
if (!isa<CXXMethodDecl>(ND))
Functions.addDecl(ND);
+ RequiresADL = false;
}
// Add any functions found via argument-dependent lookup.
@@ -12657,7 +12662,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (NumArgs == 1 || isPostIncDec) {
UnaryOperatorKind Opc
= UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
- return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First);
+ return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First,
+ RequiresADL);
}
if (Op == OO_Subscript) {
@@ -12681,8 +12687,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
- ExprResult Result
- = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions, Args[0], Args[1]);
+ ExprResult Result = SemaRef.CreateOverloadedBinOp(
+ OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL);
if (Result.isInvalid())
return ExprError();
diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp
index 52d0bff3884..dff9350cc98 100644
--- a/clang/test/SemaCXX/overloaded-operator.cpp
+++ b/clang/test/SemaCXX/overloaded-operator.cpp
@@ -550,3 +550,38 @@ namespace PR27027 {
bool test_global_1 = +a_global; // expected-error {{overload resolution selected deleted operator '+'}}
bool test_global_2 = a_global + a_global; // expected-error {{overload resolution selected deleted operator '+'}}
}
+
+namespace LateADLInNonDependentExpressions {
+ struct A {};
+ struct B : A {};
+ int &operator+(A, A);
+ int &operator!(A);
+ int &operator+=(A, A);
+ int &operator<<(A, A);
+ int &operator++(A);
+ int &operator++(A, int);
+ int &operator->*(A, A);
+
+ template<typename T> void f() {
+ // An instantiation-dependent value of type B.
+ // These are all non-dependent operator calls of type int&.
+#define idB ((void()), B())
+ int &a = idB + idB,
+ &b = !idB,
+ &c = idB += idB,
+ &d = idB << idB,
+ &e = ++idB,
+ &f = idB++,
+ &g = idB ->* idB;
+ }
+
+ // These should not be found by ADL in the template instantiation.
+ float &operator+(B, B);
+ float &operator!(B);
+ float &operator+=(B, B);
+ float &operator<<(B, B);
+ float &operator++(B);
+ float &operator++(B, int);
+ float &operator->*(B, B);
+ template void f<int>();
+}
OpenPOWER on IntegriCloud