diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/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(E->getDecl())) - if (!isConstantEvaluated() && FD->isConsteval() && - !RebuildingImmediateInvocation) + if (auto *FD = dyn_cast(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); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/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 #include @@ -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 DisableIITracking( + S.RebuildingImmediateInvocation, true); + assert(S.Context.hasSameType( FromType, S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); +#endif } else { return false; } diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -104,6 +104,87 @@ } +namespace dependent_addressing { + +template +consteval int t_f_eval(int i) { +// expected-note@-1+ {{declared here}} + return i; +} + +using func_type = int(int); + +template +auto t_f_eval_proxy() { + return &t_f_eval; +// expected-error@-1 {{take address}} +} + +template +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 +constexpr auto l_eval = [](int i) consteval { +// expected-note@-1+ {{declared here}} + + return i + y; +}; + +template +int test_templ() { + func_type* p1 = (&t_f_eval); + // expected-error@-1+ {{cannot take address of consteval function 't_f_eval<1>' outside of an immediate invocation}} + + auto ptr = &t_f_eval; + // expected-error@-1 {{take address}} + + // FIXME: AddressOfFunctionResolver breaks + // func_type* p7 = __builtin_addressof(t_f_eval); + + auto p = t_f_eval; + // expected-error@-1 {{take address}} + + auto m1 = &A::f1; + // expected-error@-1 {{take address}} + auto l1 = &decltype(l_eval)::operator(); + // expected-error@-1 {{take address}} + + auto pr = t_f_eval_proxy(); + // 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 +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 +