From: Richard Smith Date: Thu, 5 Oct 2017 19:35:51 +0000 (+0000) Subject: Fix two-phase name lookup for non-dependent overloaded operators. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6ddf39e8aa2de6022b62828f6ada82b8981e896c;p=clang Fix two-phase name lookup for non-dependent overloaded operators. If we resolve an overloaded operator call to a specific function during template definition, don't perform ADL during template instantiation. Doing so finds overloads that we're not supposed to find. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315005 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 80b6978b92..b33f63225c 100644 --- a/include/clang/Sema/Sema.h +++ b/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/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 66b252e144..0e53ffa83f 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index a9ecf721db..fa582c2213 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -12636,10 +12636,14 @@ TreeTransform::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(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::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, NamedDecl *ND = cast(Callee)->getDecl(); if (!isa(ND)) Functions.addDecl(ND); + RequiresADL = false; } // Add any functions found via argument-dependent lookup. @@ -12657,7 +12662,8 @@ TreeTransform::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::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/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp index 52d0bff388..dff9350cc9 100644 --- a/test/SemaCXX/overloaded-operator.cpp +++ b/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 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(); +}