<div dir="ltr">Hi,<div><br></div><div>it looks like this broke check-clang-tools, see e.g. <a href="http://45.33.8.238/linux/24975/step_8.txt">http://45.33.8.238/linux/24975/step_8.txt</a></div><div><br></div><div>Nico</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Aug 6, 2020 at 7:57 PM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Author: Richard Smith<br>
Date: 2020-08-06T16:56:39-07:00<br>
New Revision: ed5a18fc0399dce994aa354a33e6f981f9828647<br>
<br>
URL: <a href="https://github.com/llvm/llvm-project/commit/ed5a18fc0399dce994aa354a33e6f981f9828647" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/ed5a18fc0399dce994aa354a33e6f981f9828647</a><br>
DIFF: <a href="https://github.com/llvm/llvm-project/commit/ed5a18fc0399dce994aa354a33e6f981f9828647.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/ed5a18fc0399dce994aa354a33e6f981f9828647.diff</a><br>
<br>
LOG: PR30738: Implement two-phase name lookup for fold-expressions.<br>
<br>
Added: <br>
<br>
<br>
Modified: <br>
clang/include/clang/AST/ExprCXX.h<br>
clang/include/clang/Sema/Sema.h<br>
clang/lib/AST/ASTContext.cpp<br>
clang/lib/Parse/ParseExpr.cpp<br>
clang/lib/Sema/SemaDeclCXX.cpp<br>
clang/lib/Sema/SemaExpr.cpp<br>
clang/lib/Sema/SemaLookup.cpp<br>
clang/lib/Sema/SemaOverload.cpp<br>
clang/lib/Sema/SemaTemplate.cpp<br>
clang/lib/Sema/SemaTemplateVariadic.cpp<br>
clang/lib/Sema/TreeTransform.h<br>
clang/lib/Serialization/ASTReaderStmt.cpp<br>
clang/lib/Serialization/ASTWriterStmt.cpp<br>
clang/test/AST/ast-dump-expr-json.cpp<br>
clang/test/AST/ast-dump-expr.cpp<br>
clang/test/SemaTemplate/cxx1z-fold-expressions.cpp<br>
<br>
Removed: <br>
<br>
<br>
<br>
################################################################################<br>
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h<br>
index 3f272c96a2d8..b53bb20f7ebc 100644<br>
--- a/clang/include/clang/AST/ExprCXX.h<br>
+++ b/clang/include/clang/AST/ExprCXX.h<br>
@@ -4519,31 +4519,38 @@ class CXXFoldExpr : public Expr {<br>
friend class ASTStmtReader;<br>
friend class ASTStmtWriter;<br>
<br>
+ enum SubExpr { Callee, LHS, RHS, Count };<br>
+<br>
SourceLocation LParenLoc;<br>
SourceLocation EllipsisLoc;<br>
SourceLocation RParenLoc;<br>
// When 0, the number of expansions is not known. Otherwise, this is one more<br>
// than the number of expansions.<br>
unsigned NumExpansions;<br>
- Stmt *SubExprs[2];<br>
+ Stmt *SubExprs[SubExpr::Count];<br>
BinaryOperatorKind Opcode;<br>
<br>
public:<br>
- CXXFoldExpr(QualType T, SourceLocation LParenLoc, Expr *LHS,<br>
- BinaryOperatorKind Opcode, SourceLocation EllipsisLoc, Expr *RHS,<br>
- SourceLocation RParenLoc, Optional<unsigned> NumExpansions)<br>
+ CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee,<br>
+ SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Opcode,<br>
+ SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc,<br>
+ Optional<unsigned> NumExpansions)<br>
: Expr(CXXFoldExprClass, T, VK_RValue, OK_Ordinary), LParenLoc(LParenLoc),<br>
EllipsisLoc(EllipsisLoc), RParenLoc(RParenLoc),<br>
NumExpansions(NumExpansions ? *NumExpansions + 1 : 0), Opcode(Opcode) {<br>
- SubExprs[0] = LHS;<br>
- SubExprs[1] = RHS;<br>
+ SubExprs[SubExpr::Callee] = Callee;<br>
+ SubExprs[SubExpr::LHS] = LHS;<br>
+ SubExprs[SubExpr::RHS] = RHS;<br>
setDependence(computeDependence(this));<br>
}<br>
<br>
CXXFoldExpr(EmptyShell Empty) : Expr(CXXFoldExprClass, Empty) {}<br>
<br>
- Expr *getLHS() const { return static_cast<Expr*>(SubExprs[0]); }<br>
- Expr *getRHS() const { return static_cast<Expr*>(SubExprs[1]); }<br>
+ UnresolvedLookupExpr *getCallee() const {<br>
+ return static_cast<UnresolvedLookupExpr *>(SubExprs[SubExpr::Callee]);<br>
+ }<br>
+ Expr *getLHS() const { return static_cast<Expr*>(SubExprs[SubExpr::LHS]); }<br>
+ Expr *getRHS() const { return static_cast<Expr*>(SubExprs[SubExpr::RHS]); }<br>
<br>
/// Does this produce a right-associated sequence of operators?<br>
bool isRightFold() const {<br>
@@ -4577,10 +4584,12 @@ class CXXFoldExpr : public Expr {<br>
}<br>
<br>
// Iterators<br>
- child_range children() { return child_range(SubExprs, SubExprs + 2); }<br>
+ child_range children() {<br>
+ return child_range(SubExprs, SubExprs + SubExpr::Count);<br>
+ }<br>
<br>
const_child_range children() const {<br>
- return const_child_range(SubExprs, SubExprs + 2);<br>
+ return const_child_range(SubExprs, SubExprs + SubExpr::Count);<br>
}<br>
};<br>
<br>
<br>
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h<br>
index 7a83e0316618..b88e5578c114 100644<br>
--- a/clang/include/clang/Sema/Sema.h<br>
+++ b/clang/include/clang/Sema/Sema.h<br>
@@ -3556,6 +3556,12 @@ class Sema final {<br>
OverloadCandidateSet *CandidateSet,<br>
ExprResult *Result);<br>
<br>
+ ExprResult CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass,<br>
+ NestedNameSpecifierLoc NNSLoc,<br>
+ DeclarationNameInfo DNI,<br>
+ const UnresolvedSetImpl &Fns,<br>
+ bool PerformADL = true);<br>
+<br>
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,<br>
UnaryOperatorKind Opc,<br>
const UnresolvedSetImpl &Fns,<br>
@@ -3822,7 +3828,6 @@ class Sema final {<br>
bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class);<br>
<br>
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,<br>
- QualType T1, QualType T2,<br>
UnresolvedSetImpl &Functions);<br>
<br>
LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,<br>
@@ -5166,6 +5171,8 @@ class Sema final {<br>
BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr);<br>
ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc,<br>
Expr *LHSExpr, Expr *RHSExpr);<br>
+ void LookupBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc,<br>
+ UnresolvedSetImpl &Functions);<br>
<br>
void DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc);<br>
<br>
@@ -5846,11 +5853,12 @@ class Sema final {<br>
SourceLocation RParenLoc);<br>
<br>
/// Handle a C++1z fold-expression: ( expr op ... op expr ).<br>
- ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,<br>
+ ExprResult ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,<br>
tok::TokenKind Operator,<br>
SourceLocation EllipsisLoc, Expr *RHS,<br>
SourceLocation RParenLoc);<br>
- ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,<br>
+ ExprResult BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,<br>
+ SourceLocation LParenLoc, Expr *LHS,<br>
BinaryOperatorKind Operator,<br>
SourceLocation EllipsisLoc, Expr *RHS,<br>
SourceLocation RParenLoc,<br>
<br>
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp<br>
index 04a4c5482db7..61e39dc176a9 100644<br>
--- a/clang/lib/AST/ASTContext.cpp<br>
+++ b/clang/lib/AST/ASTContext.cpp<br>
@@ -753,10 +753,10 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,<br>
CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());<br>
<br>
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))<br>
- NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,<br>
- BinaryOperatorKind::BO_LAnd,<br>
- SourceLocation(), /*RHS=*/nullptr,<br>
- SourceLocation(), /*NumExpansions=*/None);<br>
+ NewIDC = new (C) CXXFoldExpr(<br>
+ OrigFold->getType(), /*Callee*/nullptr, SourceLocation(), NewIDC,<br>
+ BinaryOperatorKind::BO_LAnd, SourceLocation(), /*RHS=*/nullptr,<br>
+ SourceLocation(), /*NumExpansions=*/None);<br>
return NewIDC;<br>
}<br>
<br>
<br>
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp<br>
index 4f662f00e1df..a6d64cbb7507 100644<br>
--- a/clang/lib/Parse/ParseExpr.cpp<br>
+++ b/clang/lib/Parse/ParseExpr.cpp<br>
@@ -3324,8 +3324,9 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS,<br>
: diag::ext_fold_expression);<br>
<br>
T.consumeClose();<br>
- return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind,<br>
- EllipsisLoc, RHS.get(), T.getCloseLocation());<br>
+ return Actions.ActOnCXXFoldExpr(getCurScope(), T.getOpenLocation(), LHS.get(),<br>
+ Kind, EllipsisLoc, RHS.get(),<br>
+ T.getCloseLocation());<br>
}<br>
<br>
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.<br>
<br>
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp<br>
index 22bf35dbd0cb..7a0adc2694ac 100644<br>
--- a/clang/lib/Sema/SemaDeclCXX.cpp<br>
+++ b/clang/lib/Sema/SemaDeclCXX.cpp<br>
@@ -8212,7 +8212,7 @@ static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S,<br>
UnresolvedSetImpl &Operators,<br>
OverloadedOperatorKind Op) {<br>
auto Lookup = [&](OverloadedOperatorKind OO) {<br>
- Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators);<br>
+ Self.LookupOverloadedOperatorName(OO, S, Operators);<br>
};<br>
<br>
// Every defaulted operator looks up itself.<br>
<br>
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp<br>
index eec057b303e0..4931cf46cffd 100644<br>
--- a/clang/lib/Sema/SemaExpr.cpp<br>
+++ b/clang/lib/Sema/SemaExpr.cpp<br>
@@ -14177,6 +14177,19 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,<br>
return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);<br>
}<br>
<br>
+void Sema::LookupBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc,<br>
+ UnresolvedSetImpl &Functions) {<br>
+ OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);<br>
+ if (OverOp != OO_None && OverOp != OO_Equal)<br>
+ LookupOverloadedOperatorName(OverOp, S, Functions);<br>
+<br>
+ // In C++20 onwards, we may have a second operator to look up.<br>
+ if (getLangOpts().CPlusPlus20) {<br>
+ if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))<br>
+ LookupOverloadedOperatorName(ExtraOp, S, Functions);<br>
+ }<br>
+}<br>
+<br>
/// Build an overloaded binary operator expression in the given scope.<br>
static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,<br>
BinaryOperatorKind Opc,<br>
@@ -14196,23 +14209,9 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,<br>
break;<br>
}<br>
<br>
- // Find all of the overloaded operators visible from this<br>
- // point. We perform both an operator-name lookup from the local<br>
- // scope and an argument-dependent lookup based on the types of<br>
- // the arguments.<br>
+ // Find all of the overloaded operators visible from this point.<br>
UnresolvedSet<16> Functions;<br>
- OverloadedOperatorKind OverOp<br>
- = BinaryOperator::getOverloadedOperator(Opc);<br>
- if (Sc && OverOp != OO_None && OverOp != OO_Equal)<br>
- S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),<br>
- RHS->getType(), Functions);<br>
-<br>
- // In C++20 onwards, we may have a second operator to look up.<br>
- if (S.getLangOpts().CPlusPlus20) {<br>
- if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))<br>
- S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(),<br>
- RHS->getType(), Functions);<br>
- }<br>
+ S.LookupBinOp(Sc, OpLoc, Opc, Functions);<br>
<br>
// Build the (potentially-overloaded, potentially-dependent)<br>
// binary operation.<br>
@@ -14628,15 +14627,11 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,<br>
if (getLangOpts().CPlusPlus && Input->getType()->isOverloadableType() &&<br>
UnaryOperator::getOverloadedOperator(Opc) != OO_None &&<br>
!(Opc == UO_AddrOf && isQualifiedMemberAccess(Input))) {<br>
- // Find all of the overloaded operators visible from this<br>
- // point. We perform both an operator-name lookup from the local<br>
- // scope and an argument-dependent lookup based on the types of<br>
- // the arguments.<br>
+ // Find all of the overloaded operators visible from this point.<br>
UnresolvedSet<16> Functions;<br>
OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);<br>
if (S && OverOp != OO_None)<br>
- LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),<br>
- Functions);<br>
+ LookupOverloadedOperatorName(OverOp, S, Functions);<br>
<br>
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input);<br>
}<br>
<br>
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp<br>
index 5757eaf3fac0..8de1060889e2 100644<br>
--- a/clang/lib/Sema/SemaLookup.cpp<br>
+++ b/clang/lib/Sema/SemaLookup.cpp<br>
@@ -2981,7 +2981,6 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,<br>
}<br>
<br>
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,<br>
- QualType T1, QualType T2,<br>
UnresolvedSetImpl &Functions) {<br>
// C++ [over.match.oper]p3:<br>
// -- The set of non-member candidates is the result of the<br>
<br>
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp<br>
index 00563cff62cf..5a20a7990c3b 100644<br>
--- a/clang/lib/Sema/SemaOverload.cpp<br>
+++ b/clang/lib/Sema/SemaOverload.cpp<br>
@@ -12994,7 +12994,18 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,<br>
<br>
static bool IsOverloaded(const UnresolvedSetImpl &Functions) {<br>
return Functions.size() > 1 ||<br>
- (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));<br>
+ (Functions.size() == 1 &&<br>
+ isa<FunctionTemplateDecl>((*Functions.begin())->getUnderlyingDecl()));<br>
+}<br>
+<br>
+ExprResult Sema::CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass,<br>
+ NestedNameSpecifierLoc NNSLoc,<br>
+ DeclarationNameInfo DNI,<br>
+ const UnresolvedSetImpl &Fns,<br>
+ bool PerformADL) {<br>
+ return UnresolvedLookupExpr::Create(Context, NamingClass, NNSLoc, DNI,<br>
+ PerformADL, IsOverloaded(Fns),<br>
+ Fns.begin(), Fns.end());<br>
}<br>
<br>
/// Create a unary operation that may resolve to an overloaded<br>
@@ -13047,10 +13058,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,<br>
CurFPFeatureOverrides());<br>
<br>
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators<br>
- UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(<br>
- Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo,<br>
- /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end());<br>
- return CXXOperatorCallExpr::Create(Context, Op, Fn, ArgsArray,<br>
+ ExprResult Fn = CreateUnresolvedLookupExpr(<br>
+ NamingClass, NestedNameSpecifierLoc(), OpNameInfo, Fns);<br>
+ if (Fn.isInvalid())<br>
+ return ExprError();<br>
+ return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), ArgsArray,<br>
Context.DependentTy, VK_RValue, OpLoc,<br>
CurFPFeatureOverrides());<br>
}<br>
@@ -13309,10 +13321,11 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,<br>
// TODO: provide better source location info in DNLoc component.<br>
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);<br>
DeclarationNameInfo OpNameInfo(OpName, OpLoc);<br>
- UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(<br>
- Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo,<br>
- /*ADL*/ PerformADL, IsOverloaded(Fns), Fns.begin(), Fns.end());<br>
- return CXXOperatorCallExpr::Create(Context, Op, Fn, Args,<br>
+ ExprResult Fn = CreateUnresolvedLookupExpr(<br>
+ NamingClass, NestedNameSpecifierLoc(), OpNameInfo, Fns, PerformADL);<br>
+ if (Fn.isInvalid())<br>
+ return ExprError();<br>
+ return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), Args,<br>
Context.DependentTy, VK_RValue, OpLoc,<br>
CurFPFeatureOverrides());<br>
}<br>
@@ -13776,15 +13789,13 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,<br>
// CHECKME: no 'operator' keyword?<br>
DeclarationNameInfo OpNameInfo(OpName, LLoc);<br>
OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));<br>
- UnresolvedLookupExpr *Fn<br>
- = UnresolvedLookupExpr::Create(Context, NamingClass,<br>
- NestedNameSpecifierLoc(), OpNameInfo,<br>
- /*ADL*/ true, /*Overloaded*/ false,<br>
- UnresolvedSetIterator(),<br>
- UnresolvedSetIterator());<br>
+ ExprResult Fn = CreateUnresolvedLookupExpr(<br>
+ NamingClass, NestedNameSpecifierLoc(), OpNameInfo, UnresolvedSet<0>());<br>
+ if (Fn.isInvalid())<br>
+ return ExprError();<br>
// Can't add any actual overloads yet<br>
<br>
- return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn, Args,<br>
+ return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn.get(), Args,<br>
Context.DependentTy, VK_RValue, RLoc,<br>
CurFPFeatureOverrides());<br>
}<br>
@@ -14727,12 +14738,12 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,<br>
return FRS_DiagnosticIssued;<br>
}<br>
} else {<br>
- UnresolvedSet<0> FoundNames;<br>
- UnresolvedLookupExpr *Fn =<br>
- UnresolvedLookupExpr::Create(Context, /*NamingClass=*/nullptr,<br>
- NestedNameSpecifierLoc(), NameInfo,<br>
- /*NeedsADL=*/true, /*Overloaded=*/false,<br>
- FoundNames.begin(), FoundNames.end());<br>
+ ExprResult FnR = CreateUnresolvedLookupExpr(/*NamingClass=*/nullptr,<br>
+ NestedNameSpecifierLoc(),<br>
+ NameInfo, UnresolvedSet<0>());<br>
+ if (FnR.isInvalid())<br>
+ return FRS_DiagnosticIssued;<br>
+ UnresolvedLookupExpr *Fn = cast<UnresolvedLookupExpr>(FnR.get());<br>
<br>
bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, Range, Loc,<br>
CandidateSet, CallExpr);<br>
<br>
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp<br>
index 3991f2b47977..5d037e58de51 100644<br>
--- a/clang/lib/Sema/SemaTemplate.cpp<br>
+++ b/clang/lib/Sema/SemaTemplate.cpp<br>
@@ -1176,7 +1176,11 @@ static ExprResult formImmediatelyDeclaredConstraint(<br>
// template<C1... T> struct s1;<br>
//<br>
// The constraint: (C1<T> && ...)<br>
- return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),<br>
+ //<br>
+ // Note that the type of C1<T> is known to be 'bool', so we don't need to do<br>
+ // any unqualified lookups for 'operator&&' here.<br>
+ return S.BuildCXXFoldExpr(/*UnqualifiedLookup=*/nullptr,<br>
+ /*LParenLoc=*/SourceLocation(),<br>
ImmediatelyDeclaredConstraint.get(), BO_LAnd,<br>
EllipsisLoc, /*RHS=*/nullptr,<br>
/*RParenLoc=*/SourceLocation(),<br>
<br>
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp<br>
index 259cc5165776..c95d67b7c732 100644<br>
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp<br>
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp<br>
@@ -1160,7 +1160,7 @@ static void CheckFoldOperand(Sema &S, Expr *E) {<br>
}<br>
}<br>
<br>
-ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,<br>
+ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,<br>
tok::TokenKind Operator,<br>
SourceLocation EllipsisLoc, Expr *RHS,<br>
SourceLocation RParenLoc) {<br>
@@ -1202,18 +1202,37 @@ ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,<br>
}<br>
<br>
BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator);<br>
- return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,<br>
+<br>
+ // Perform first-phase name lookup now.<br>
+ UnresolvedLookupExpr *ULE = nullptr;<br>
+ {<br>
+ UnresolvedSet<16> Functions;<br>
+ LookupBinOp(S, EllipsisLoc, Opc, Functions);<br>
+ if (!Functions.empty()) {<br>
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(<br>
+ BinaryOperator::getOverloadedOperator(Opc));<br>
+ ExprResult Callee = CreateUnresolvedLookupExpr(<br>
+ /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),<br>
+ DeclarationNameInfo(OpName, EllipsisLoc), Functions);<br>
+ if (Callee.isInvalid())<br>
+ return ExprError();<br>
+ ULE = cast<UnresolvedLookupExpr>(Callee.get());<br>
+ }<br>
+ }<br>
+<br>
+ return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,<br>
None);<br>
}<br>
<br>
-ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,<br>
+ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,<br>
+ SourceLocation LParenLoc, Expr *LHS,<br>
BinaryOperatorKind Operator,<br>
SourceLocation EllipsisLoc, Expr *RHS,<br>
SourceLocation RParenLoc,<br>
Optional<unsigned> NumExpansions) {<br>
- return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS,<br>
- Operator, EllipsisLoc, RHS, RParenLoc,<br>
- NumExpansions);<br>
+ return new (Context)<br>
+ CXXFoldExpr(Context.DependentTy, Callee, LParenLoc, LHS, Operator,<br>
+ EllipsisLoc, RHS, RParenLoc, NumExpansions);<br>
}<br>
<br>
ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,<br>
<br>
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h<br>
index 53064d28dd99..29d263de6e88 100644<br>
--- a/clang/lib/Sema/TreeTransform.h<br>
+++ b/clang/lib/Sema/TreeTransform.h<br>
@@ -3583,13 +3583,15 @@ class TreeTransform {<br>
///<br>
/// By default, performs semantic analysis in order to build a new fold<br>
/// expression.<br>
- ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS,<br>
+ ExprResult RebuildCXXFoldExpr(UnresolvedLookupExpr *ULE,<br>
+ SourceLocation LParenLoc, Expr *LHS,<br>
BinaryOperatorKind Operator,<br>
SourceLocation EllipsisLoc, Expr *RHS,<br>
SourceLocation RParenLoc,<br>
Optional<unsigned> NumExpansions) {<br>
- return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc,<br>
- RHS, RParenLoc, NumExpansions);<br>
+ return getSema().BuildCXXFoldExpr(ULE, LParenLoc, LHS, Operator,<br>
+ EllipsisLoc, RHS, RParenLoc,<br>
+ NumExpansions);<br>
}<br>
<br>
/// Build an empty C++1z fold-expression with the given operator.<br>
@@ -13128,6 +13130,14 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr(<br>
template<typename Derived><br>
ExprResult<br>
TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {<br>
+ UnresolvedLookupExpr *Callee = nullptr;<br>
+ if (Expr *OldCallee = E->getCallee()) {<br>
+ ExprResult CalleeResult = getDerived().TransformExpr(OldCallee);<br>
+ if (CalleeResult.isInvalid())<br>
+ return ExprError();<br>
+ Callee = cast<UnresolvedLookupExpr>(CalleeResult.get());<br>
+ }<br>
+<br>
Expr *Pattern = E->getPattern();<br>
<br>
SmallVector<UnexpandedParameterPack, 2> Unexpanded;<br>
@@ -13167,8 +13177,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {<br>
return E;<br>
<br>
return getDerived().RebuildCXXFoldExpr(<br>
- E->getBeginLoc(), LHS.get(), E->getOperator(), E->getEllipsisLoc(),<br>
- RHS.get(), E->getEndLoc(), NumExpansions);<br>
+ Callee, E->getBeginLoc(), LHS.get(), E->getOperator(),<br>
+ E->getEllipsisLoc(), RHS.get(), E->getEndLoc(), NumExpansions);<br>
}<br>
<br>
// The transform has determined that we should perform an elementwise<br>
@@ -13188,8 +13198,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {<br>
return true;<br>
<br>
Result = getDerived().RebuildCXXFoldExpr(<br>
- E->getBeginLoc(), Out.get(), E->getOperator(), E->getEllipsisLoc(),<br>
- Result.get(), E->getEndLoc(), OrigNumExpansions);<br>
+ Callee, E->getBeginLoc(), Out.get(), E->getOperator(),<br>
+ E->getEllipsisLoc(), Result.get(), E->getEndLoc(), OrigNumExpansions);<br>
if (Result.isInvalid())<br>
return true;<br>
}<br>
@@ -13204,16 +13214,21 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {<br>
if (Out.get()->containsUnexpandedParameterPack()) {<br>
// We still have a pack; retain a pack expansion for this slice.<br>
Result = getDerived().RebuildCXXFoldExpr(<br>
- E->getBeginLoc(), LeftFold ? Result.get() : Out.get(),<br>
+ Callee, E->getBeginLoc(), LeftFold ? Result.get() : Out.get(),<br>
E->getOperator(), E->getEllipsisLoc(),<br>
LeftFold ? Out.get() : Result.get(), E->getEndLoc(),<br>
OrigNumExpansions);<br>
} else if (Result.isUsable()) {<br>
// We've got down to a single element; build a binary operator.<br>
- Result = getDerived().RebuildBinaryOperator(<br>
- E->getEllipsisLoc(), E->getOperator(),<br>
- LeftFold ? Result.get() : Out.get(),<br>
- LeftFold ? Out.get() : Result.get());<br>
+ Expr *LHS = LeftFold ? Result.get() : Out.get();<br>
+ Expr *RHS = LeftFold ? Out.get() : Result.get();<br>
+ if (Callee)<br>
+ Result = getDerived().RebuildCXXOperatorCallExpr(<br>
+ BinaryOperator::getOverloadedOperator(E->getOperator()),<br>
+ E->getEllipsisLoc(), Callee, LHS, RHS);<br>
+ else<br>
+ Result = getDerived().RebuildBinaryOperator(E->getEllipsisLoc(),<br>
+ E->getOperator(), LHS, RHS);<br>
} else<br>
Result = Out;<br>
<br>
@@ -13231,8 +13246,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {<br>
return true;<br>
<br>
Result = getDerived().RebuildCXXFoldExpr(<br>
- E->getBeginLoc(), Result.get(), E->getOperator(), E->getEllipsisLoc(),<br>
- Out.get(), E->getEndLoc(), OrigNumExpansions);<br>
+ Callee, E->getBeginLoc(), Result.get(), E->getOperator(),<br>
+ E->getEllipsisLoc(), Out.get(), E->getEndLoc(), OrigNumExpansions);<br>
if (Result.isInvalid())<br>
return true;<br>
}<br>
<br>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp<br>
index 2715c7f3f191..1b8699b78b7d 100644<br>
--- a/clang/lib/Serialization/ASTReaderStmt.cpp<br>
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp<br>
@@ -2154,6 +2154,7 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {<br>
E->NumExpansions = Record.readInt();<br>
E->SubExprs[0] = Record.readSubExpr();<br>
E->SubExprs[1] = Record.readSubExpr();<br>
+ E->SubExprs[2] = Record.readSubExpr();<br>
E->Opcode = (BinaryOperatorKind)Record.readInt();<br>
}<br>
<br>
<br>
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp<br>
index d977c4e53535..da61d88c684c 100644<br>
--- a/clang/lib/Serialization/ASTWriterStmt.cpp<br>
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp<br>
@@ -2053,6 +2053,7 @@ void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {<br>
Record.push_back(E->NumExpansions);<br>
Record.AddStmt(E->SubExprs[0]);<br>
Record.AddStmt(E->SubExprs[1]);<br>
+ Record.AddStmt(E->SubExprs[2]);<br>
Record.push_back(E->Opcode);<br>
Code = serialization::EXPR_CXX_FOLD;<br>
}<br>
<br>
diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp<br>
index 245c56cafdae..02bd8c470d5a 100644<br>
--- a/clang/test/AST/ast-dump-expr-json.cpp<br>
+++ b/clang/test/AST/ast-dump-expr-json.cpp<br>
@@ -7587,6 +7587,7 @@ void TestNonADLCall3() {<br>
// CHECK-NEXT: },<br>
// CHECK-NEXT: "valueCategory": "rvalue",<br>
// CHECK-NEXT: "inner": [<br>
+// CHECK-NEXT: {},<br>
// CHECK-NEXT: {<br>
// CHECK-NEXT: "id": "0x{{.*}}",<br>
// CHECK-NEXT: "kind": "DeclRefExpr",<br>
@@ -7640,6 +7641,7 @@ void TestNonADLCall3() {<br>
// CHECK-NEXT: "valueCategory": "rvalue",<br>
// CHECK-NEXT: "inner": [<br>
// CHECK-NEXT: {},<br>
+// CHECK-NEXT: {},<br>
// CHECK-NEXT: {<br>
// CHECK-NEXT: "id": "0x{{.*}}",<br>
// CHECK-NEXT: "kind": "DeclRefExpr",<br>
@@ -7691,6 +7693,7 @@ void TestNonADLCall3() {<br>
// CHECK-NEXT: },<br>
// CHECK-NEXT: "valueCategory": "rvalue",<br>
// CHECK-NEXT: "inner": [<br>
+// CHECK-NEXT: {},<br>
// CHECK-NEXT: {<br>
// CHECK-NEXT: "id": "0x{{.*}}",<br>
// CHECK-NEXT: "kind": "DeclRefExpr",<br>
<br>
diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp<br>
index 33b00f6d6e6d..747a6a5cd539 100644<br>
--- a/clang/test/AST/ast-dump-expr.cpp<br>
+++ b/clang/test/AST/ast-dump-expr.cpp<br>
@@ -523,16 +523,19 @@ void PrimaryExpressions(Ts... a) {<br>
<br>
(a + ...);<br>
// CHECK: CXXFoldExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:11> '<dependent type>'<br>
+ // CHECK-NEXT: <<<NULL>>><br>
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...'<br>
// CHECK-NEXT: <<<NULL>>><br>
<br>
(... + a);<br>
// CHECK: CXXFoldExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:11> '<dependent type>'<br>
// CHECK-NEXT: <<<NULL>>><br>
+ // CHECK-NEXT: <<<NULL>>><br>
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:10> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...'<br>
<br>
(a + ... + b);<br>
// CHECK: CXXFoldExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:15> '<dependent type>'<br>
+ // CHECK-NEXT: <<<NULL>>><br>
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...'<br>
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:14> 'int' lvalue Var 0x{{[^ ]*}} 'b' 'int'<br>
}<br>
<br>
diff --git a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp<br>
index 44f388843b39..518eaf0e0523 100644<br>
--- a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp<br>
+++ b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp<br>
@@ -102,3 +102,25 @@ namespace PR41845 {<br>
<br>
Sum<1>::type<1, 2> x; // expected-note {{instantiation of}}<br>
}<br>
+<br>
+namespace PR30738 {<br>
+ namespace N {<br>
+ struct S {};<br>
+ }<br>
+<br>
+ namespace T {<br>
+ void operator+(N::S, N::S) {}<br>
+ template<typename ...Ts> void f() { (Ts{} + ...); }<br>
+ }<br>
+<br>
+ void g() { T::f<N::S, N::S>(); }<br>
+<br>
+ template<typename T, typename ...U> auto h(U ...v) {<br>
+ T operator+(T, T); // expected-note {{candidate}}<br>
+ return (v + ...); // expected-error {{invalid operands}}<br>
+ }<br>
+ int test_h1 = h<N::S>(1, 2, 3);<br>
+ N::S test_h2 = h<N::S>(N::S(), N::S(), N::S());<br>
+ int test_h3 = h<struct X>(1, 2, 3);<br>
+ N::S test_h4 = h<struct X>(N::S(), N::S(), N::S()); // expected-note {{instantiation of}}<br>
+}<br>
<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>