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}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits