wchilders created this revision. wchilders added reviewers: Tyker, rsmith. Herald added a project: clang. Herald added a subscriber: cfe-commits. wchilders requested review of this revision.
Previously dependent references to consteval (`ReferenceToConsteval`) were tracked, and dependent expressions were evaluated as possible immediate invocations. This resulted in the evaluation of value dependent expressions. This patch also suppresses duplicated diagnostics in debug builds while working with templates caused by the side effects of `FixOverloadedFunctionReference`. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D85933 Files: clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaOverload.cpp clang/test/SemaCXX/cxx2a-consteval.cpp
Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -104,6 +104,87 @@ } +namespace dependent_addressing { + +template<int y> +consteval int t_f_eval(int i) { +// expected-note@-1+ {{declared here}} + return i; +} + +using func_type = int(int); + +template<int y> +auto t_f_eval_proxy() { + return &t_f_eval<y>; +// expected-error@-1 {{take address}} +} + +template<int y> +struct A { + consteval int f1(int i) const { +// expected-note@-1 {{declared here}} + return i + y; + } + consteval A(int i); + consteval A() = default; + consteval ~A() = default; // expected-error {{destructor cannot be declared consteval}} +}; + +template<int y> +constexpr auto l_eval = [](int i) consteval { +// expected-note@-1+ {{declared here}} + + return i + y; +}; + +template<int y> +int test_templ() { + func_type* p1 = (&t_f_eval<y>); + // expected-error@-1+ {{cannot take address of consteval function 't_f_eval<1>' outside of an immediate invocation}} + + auto ptr = &t_f_eval<y>; + // expected-error@-1 {{take address}} + + // FIXME: AddressOfFunctionResolver breaks + // func_type* p7 = __builtin_addressof(t_f_eval<y>); + + auto p = t_f_eval<y>; + // expected-error@-1 {{take address}} + + auto m1 = &A<y>::f1; + // expected-error@-1 {{take address}} + auto l1 = &decltype(l_eval<y>)::operator(); + // expected-error@-1 {{take address}} + + auto pr = t_f_eval_proxy<y>(); + // expected-note@-1 {{in instantiation of function template specialization}} + + return 0; +} + +auto tr = test_templ<1>(); +// expected-note@-1+ {{in instantiation of function template specialization}} + +} // namespace dependent_addressing + +namespace dependent_call { + +consteval int cf1(int y) { + return y; +} + +template<int y> +auto f1() { + constexpr int x = cf1(y); + return x; +} + +auto f1r = f1<1>(); + +} // namespace dependent_call + + namespace invalid_function { struct A { @@ -593,4 +674,5 @@ { Copy* c; c = new Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); }// expected-error {{is not a constant expression}} expected-note {{to a consteval}} } -} // namespace special_ctor +} // namespace copy_ctor + Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -34,6 +34,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/SaveAndRestore.h" #include <algorithm> #include <cstdlib> @@ -1750,11 +1751,19 @@ } // Check that we've computed the proper type after overload resolution. +#ifndef NDEBUG // FIXME: FixOverloadedFunctionReference has side-effects; we shouldn't // be calling it from within an NDEBUG block. + + // This is a hack to prevent duplicated diagnostics triggered by + // the above side effects in some cases involving immediate invocations. + llvm::SaveAndRestore<bool> DisableIITracking( + S.RebuildingImmediateInvocation, true); + assert(S.Context.hasSameType( FromType, S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); +#endif } else { return false; } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16146,11 +16146,13 @@ } ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { + // Skip checking dependent expressions - If we allow dependent expressions + // we end up evaluating dependent constant expressions. if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || - RebuildingImmediateInvocation) + E.get()->getDependence() || RebuildingImmediateInvocation) return E; - /// Opportunistically remove the callee from ReferencesToConsteval if we can. + /// Opportunistically remove the callee from ReferenceToConsteval if we can. /// It's OK if this fails; we'll also remove this in /// HandleImmediateInvocations, but catching it here allows us to avoid /// walking the AST looking for it in simple cases. @@ -18109,10 +18111,18 @@ !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; - if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) - if (!isConstantEvaluated() && FD->isConsteval() && - !RebuildingImmediateInvocation) + if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) { + // Skip checking dependent contexts - If we attempt to check + // dependent contexts here, we end up increasing the guarantee on + // CheckForImmediateInvocation's opportunistic removal from + // ReferenceToConsteval to guaranteed removal -- to prevent + // incorrect diagnostics. This would require an additional AST + // walk to ensure the reference was removed. + if (FD->isConsteval() && !isConstantEvaluated() && + !CurContext->isDependentContext() && !RebuildingImmediateInvocation) ExprEvalContexts.back().ReferenceToConsteval.insert(E); + } + MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits