aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-12-03 00:25:51 +0100
committerJakub Jelinek <jakub@redhat.com>2020-12-03 00:40:33 +0100
commitba3d8dffcc1c23b30370ab24fc20d09cff005d7b (patch)
treee4ea6a9a8e575d5f90fdc95c71e3e56bb94816cc /gcc/cp
parent2cace1cd683318e83e8a613f1aa2f2b16e37a342 (diff)
downloadgcc-ba3d8dffcc1c23b30370ab24fc20d09cff005d7b.zip
gcc-ba3d8dffcc1c23b30370ab24fc20d09cff005d7b.tar.gz
gcc-ba3d8dffcc1c23b30370ab24fc20d09cff005d7b.tar.bz2
c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
While std::source_location::current () is static consteval source_location current() noexcept; in the standard, it also says with LWG3396: "Any call to current that appears as a default member initializer ([class.mem]), or as a subexpression thereof, should correspond to the location of the constructor definition or aggregate initialization that uses the default member initializer. Any call to current that appears as a default argument ([dcl.fct.default]), or as a subexpression thereof, should correspond to the location of the invocation of the function that uses the default argument ([expr.call])." so it must work as compiler magic rather than normal immediate functions, in particular we need to defer its evaluation when parsing default arguments or nsdmis. This patch actually defers evaluation of all the calls to std::source_location::current () until genericization (or constant expression evaluation when called from constant expression contexts). I had to change constexpr.c too so that it temporarily adjusts current_function_decl from the constexpr evaluation context, but we do the same already from __builtin_FUNCTION (). 2020-12-03 Jakub Jelinek <jakub@redhat.com> PR c++/80780 PR c++/93093 * cp-tree.h (source_location_current_p): Declare. * tree.c (source_location_current_p): New function. * call.c (immediate_invocation_p): New function. (build_over_call): Use it to resolve LWG3396. * constexpr.c (cxx_eval_builtin_function_call): Temporarily set current_function_decl from ctx->call->fundef->decl if any. * cp-gimplify.c (cp_genericize_r) <case CALL_EXPR>: Fold calls to immediate function std::source_location::current (). * g++.dg/cpp2a/srcloc15.C: New test. * g++.dg/cpp2a/srcloc16.C: New test. * g++.dg/cpp2a/srcloc17.C: New test. * g++.dg/cpp2a/srcloc18.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/call.c35
-rw-r--r--gcc/cp/constexpr.c7
-rw-r--r--gcc/cp/cp-gimplify.c8
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/tree.c26
5 files changed, 62 insertions, 15 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3a6ad13..f1e0bcb 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8540,6 +8540,25 @@ build_trivial_dtor_call (tree instance, bool no_ptr_deref)
instance, clobber);
}
+/* Return true if a call to FN with number of arguments NARGS
+ is an immediate invocation. */
+
+static bool
+immediate_invocation_p (tree fn, int nargs)
+{
+ return (TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (fn)
+ && cp_unevaluated_operand == 0
+ && (current_function_decl == NULL_TREE
+ || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
+ && (current_binding_level->kind != sk_function_parms
+ || !current_binding_level->immediate_fn_ctx_p)
+ /* As an exception, we defer std::source_location::current ()
+ invocations until genericization because LWG3396 mandates
+ special behavior for it. */
+ && (nargs > 1 || !source_location_current_p (fn)));
+}
+
/* Subroutine of the various build_*_call functions. Overload resolution
has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a
@@ -8607,13 +8626,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
addr, nargs, argarray);
if (TREE_THIS_VOLATILE (fn) && cfun)
current_function_returns_abnormally = 1;
- if (TREE_CODE (fn) == FUNCTION_DECL
- && DECL_IMMEDIATE_FUNCTION_P (fn)
- && cp_unevaluated_operand == 0
- && (current_function_decl == NULL_TREE
- || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
- && (current_binding_level->kind != sk_function_parms
- || !current_binding_level->immediate_fn_ctx_p))
+ if (immediate_invocation_p (fn, nargs))
{
tree obj_arg = NULL_TREE, exprimm = expr;
if (DECL_CONSTRUCTOR_P (fn))
@@ -9251,13 +9264,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (TREE_CODE (fn) == ADDR_EXPR)
{
tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
- if (TREE_CODE (fndecl) == FUNCTION_DECL
- && DECL_IMMEDIATE_FUNCTION_P (fndecl)
- && cp_unevaluated_operand == 0
- && (current_function_decl == NULL_TREE
- || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
- && (current_binding_level->kind != sk_function_parms
- || !current_binding_level->immediate_fn_ctx_p))
+ if (immediate_invocation_p (fndecl, nargs))
{
tree obj_arg = NULL_TREE;
if (DECL_CONSTRUCTOR_P (fndecl))
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 9a1a1db..cd34e8e 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1332,7 +1332,12 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
}
if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
- return fold_builtin_source_location (EXPR_LOCATION (t));
+ {
+ temp_override<tree> ovr (current_function_decl);
+ if (ctx->call && ctx->call->fundef)
+ current_function_decl = ctx->call->fundef->decl;
+ return fold_builtin_source_location (EXPR_LOCATION (t));
+ }
int strops = 0;
int strret = 0;
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 064a44c..84b8d16 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1374,6 +1374,14 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
break;
}
+ if (tree fndecl = cp_get_callee_fndecl (stmt))
+ if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
+ {
+ gcc_assert (source_location_current_p (fndecl));
+ *stmt_p = cxx_constant_value (stmt);
+ break;
+ }
+
if (!wtd->no_sanitize_p
&& sanitize_flags_p ((SANITIZE_NULL
| SANITIZE_ALIGNMENT | SANITIZE_VPTR)))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 156bd6c..d77ec11 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7478,6 +7478,7 @@ extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
+extern bool source_location_current_p (tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
extern tree replace_placeholders (tree, tree, bool * = NULL);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 5932777..4d9efb7 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2993,6 +2993,32 @@ array_type_nelts_total (tree type)
return sz;
}
+/* Return true if FNDECL is std::source_location::current () method. */
+
+bool
+source_location_current_p (tree fndecl)
+{
+ gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (fndecl));
+ if (DECL_NAME (fndecl) == NULL_TREE
+ || TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != RECORD_TYPE
+ || DECL_CONTEXT (fndecl) != TREE_TYPE (TREE_TYPE (fndecl))
+ || !id_equal (DECL_NAME (fndecl), "current"))
+ return false;
+
+ tree source_location = DECL_CONTEXT (fndecl);
+ if (TYPE_NAME (source_location) == NULL_TREE
+ || TREE_CODE (TYPE_NAME (source_location)) != TYPE_DECL
+ || TYPE_IDENTIFIER (source_location) == NULL_TREE
+ || !id_equal (TYPE_IDENTIFIER (source_location),
+ "source_location")
+ || !decl_in_std_namespace_p (TYPE_NAME (source_location)))
+ return false;
+
+ return true;
+}
+
struct bot_data
{
splay_tree target_remap;