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