diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -463,6 +463,8 @@ - Fix crash when passing a braced initializer list to a parentehsized aggregate initialization expression. (`#63008 `_). +- Fix reject-valid when consteval operator appears inside of a template. + (`#62886 `_). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3037,10 +3037,11 @@ /// argument-dependent lookup, etc. Subclasses may override this routine to /// provide different behavior. ExprResult RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, - SourceLocation OpLoc, - Expr *Callee, - Expr *First, - Expr *Second); + SourceLocation OpLoc, + SourceLocation CalleeLoc, + bool RequiresADL, + const UnresolvedSetImpl &Functions, + Expr *First, Expr *Second); /// Build a new C++ "named" cast expression, such as static_cast or /// reinterpret_cast. @@ -11937,10 +11938,6 @@ llvm_unreachable("not an overloaded operator?"); } - ExprResult Callee = getDerived().TransformExpr(E->getCallee()); - if (Callee.isInvalid()) - return ExprError(); - ExprResult First; if (E->getOperator() == OO_Amp) First = getDerived().TransformAddressOfOperand(E->getArg(0)); @@ -11957,23 +11954,41 @@ return ExprError(); } - if (!getDerived().AlwaysRebuild() && - Callee.get() == E->getCallee() && - First.get() == E->getArg(0) && - (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) - return SemaRef.MaybeBindToTemporary(E); - Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); FPOptionsOverride NewOverrides(E->getFPFeatures()); getSema().CurFPFeatures = NewOverrides.applyOverrides(getSema().getLangOpts()); getSema().FpPragmaStack.CurrentValue = NewOverrides; - return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), - E->getOperatorLoc(), - Callee.get(), - First.get(), - Second.get()); + bool RequiresADL = false; + Expr *Callee = E->getCallee(); + if (UnresolvedLookupExpr *ULE = dyn_cast(Callee)) { + RequiresADL = ULE->requiresADL(); + LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), + Sema::LookupOrdinaryName); + if (getDerived().TransformOverloadExprDecls(ULE, ULE->requiresADL(), R)) + return ExprError(); + + return getDerived().RebuildCXXOperatorCallExpr( + E->getOperator(), E->getOperatorLoc(), Callee->getBeginLoc(), + RequiresADL, R.asUnresolvedSet(), First.get(), Second.get()); + } + + UnresolvedSet<16> Functions; + if (ImplicitCastExpr *ICE = dyn_cast(Callee)) + Callee = ICE->getSubExprAsWritten(); + NamedDecl *DR = cast(Callee)->getDecl(); + ValueDecl *VD = cast_or_null( + getDerived().TransformDecl(DR->getLocation(), DR)); + if (!VD) + return ExprError(); + + if (!isa(VD)) + Functions.addDecl(VD); + + return getDerived().RebuildCXXOperatorCallExpr( + E->getOperator(), E->getOperatorLoc(), Callee->getBeginLoc(), RequiresADL, + Functions, First.get(), Second.get()); } template @@ -14083,13 +14098,17 @@ // We've got down to a single element; build a binary operator. Expr *LHS = LeftFold ? Result.get() : Out.get(); Expr *RHS = LeftFold ? Out.get() : Result.get(); - if (Callee) + if (Callee) { + UnresolvedSet<16> Functions; + Functions.append(Callee->decls_begin(), Callee->decls_end()); Result = getDerived().RebuildCXXOperatorCallExpr( BinaryOperator::getOverloadedOperator(E->getOperator()), - E->getEllipsisLoc(), Callee, LHS, RHS); - else + E->getEllipsisLoc(), Callee->getBeginLoc(), Callee->requiresADL(), + Functions, LHS, RHS); + } else { Result = getDerived().RebuildBinaryOperator(E->getEllipsisLoc(), E->getOperator(), LHS, RHS); + } } else Result = Out; @@ -15093,14 +15112,11 @@ return Template.get(); } -template -ExprResult -TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, - SourceLocation OpLoc, - Expr *OrigCallee, - Expr *First, - Expr *Second) { - Expr *Callee = OrigCallee->IgnoreParenCasts(); +template +ExprResult TreeTransform::RebuildCXXOperatorCallExpr( + OverloadedOperatorKind Op, SourceLocation OpLoc, SourceLocation CalleeLoc, + bool RequiresADL, const UnresolvedSetImpl &Functions, Expr *First, + Expr *Second) { bool isPostIncDec = Second && (Op == OO_PlusPlus || Op == OO_MinusMinus); if (First->getObjectKind() == OK_ObjCProperty) { @@ -15125,8 +15141,8 @@ if (Op == OO_Subscript) { if (!First->getType()->isOverloadableType() && !Second->getType()->isOverloadableType()) - return getSema().CreateBuiltinArraySubscriptExpr( - First, Callee->getBeginLoc(), Second, OpLoc); + return getSema().CreateBuiltinArraySubscriptExpr(First, CalleeLoc, Second, + OpLoc); } else if (Op == OO_Arrow) { // It is possible that the type refers to a RecoveryExpr created earlier // in the tree transformation. @@ -15160,27 +15176,6 @@ } } - // 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)) { - 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, - // CreateOverloaded* will find that function for us. - NamedDecl *ND = cast(Callee)->getDecl(); - if (!isa(ND)) - Functions.addDecl(ND); - RequiresADL = false; - } - // Add any functions found via argument-dependent lookup. Expr *Args[2] = { First, Second }; unsigned NumArgs = 1 + (Second != nullptr); @@ -15193,22 +15188,11 @@ RequiresADL); } - if (Op == OO_Subscript) { - SourceLocation LBrace; - SourceLocation RBrace; - - if (DeclRefExpr *DRE = dyn_cast(Callee)) { - DeclarationNameLoc NameLoc = DRE->getNameInfo().getInfo(); - LBrace = NameLoc.getCXXOperatorNameBeginLoc(); - RBrace = NameLoc.getCXXOperatorNameEndLoc(); - } else { - LBrace = Callee->getBeginLoc(); - RBrace = OpLoc; - } - - return SemaRef.CreateOverloadedArraySubscriptExpr(LBrace, RBrace, - First, Second); - } + // FIXME: The following code for subscript expression is either never executed + // or not tested by check-clang. + if (Op == OO_Subscript) + return SemaRef.CreateOverloadedArraySubscriptExpr(CalleeLoc, OpLoc, First, + Second); // Create the overloaded operator invocation for binary operators. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); diff --git a/clang/test/SemaCXX/consteval-operators.cpp b/clang/test/SemaCXX/consteval-operators.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/consteval-operators.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -std=c++2a -emit-llvm-only -Wno-unused-value %s -verify + +// expected-no-diagnostics + +struct A { + consteval A operator+() { return {}; } +}; +consteval A operator~(A) { return {}; } +consteval A operator+(A, A) { return {}; } + +template void f() { + A a; + A b = ~a; + A c = a + a; + A d = +a; +} +template void f(); + +template void foo() { + T a; + T b = ~a; + T c = a + a; + T d = +a; +} + +template void foo(); + +template struct B { DataT D; }; + +template +consteval B operator+(B lhs, B rhs) { + return B{lhs.D + rhs.D}; +} + +template consteval T template_add(T a, T b) { return a + b; } + +consteval B non_template_add(B a, B b) { return a + b; } + +void bar() { + constexpr B a{}; + constexpr B b{}; + auto constexpr c = a + b; +} + +static_assert((template_add(B{7}, B{3})).D == 10); +static_assert((non_template_add(B{7}, B{3})).D == 10); diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -585,3 +585,16 @@ float &operator->*(B, B); template void f(); } + +namespace test { +namespace A { +template T f(T t) { + T operator+(T, T); + return t + t; +} +} +namespace B { + struct X {}; +} +void g(B::X x) { A::f(x); } +}