c++: modules and std::source_location::current() def arg [PR100881]

We currently declare __builtin_source_location with a const void* return
type instead of the actual type const std::source_location::__impl*, and
later when folding this builtin we obtain the actual type via name lookup.

But the below testcase demonstrates this approach seems to interact
poorly with modules, since we may import an entity that uses
std::source_location::current() in its default argument (or DMI) without
necessarily importing <source_location>, and thus the name lookup for
std::source_location will fail at the call site (when using the default
argument) unless we also import <source_location>.

This patch fixes this by instead initially declaring the builtin with an
auto return type and updating it appropriately upon its first use (in
standard code the first/only use would be in the definition of
std::source_location).  Thus when folding calls to this builtin we can
get at its return type through the type of the CALL_EXPR and avoid
needing to do a name lookup.

	PR c++/100881

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_builtin_function_call): Adjust calls
	to fold_builtin_source_location.
	* cp-gimplify.cc (cp_gimplify_expr): Likewise.
	(cp_fold): Likewise.
	(get_source_location_impl_type): Remove location_t parameter and
	adjust accordingly.  No longer static.
	(fold_builtin_source_location): Take a CALL_EXPR tree instead of a
	location and obtain the impl type from its return type.
	* cp-tree.h (enum cp_tree_index): Remove CPTI_SOURCE_LOCATION_IMPL
	enumerator.
	(source_location_impl): Remove.
	(fold_builtin_source_location): Adjust parameter type.
	(get_source_location_impl_type): Declare.
	* decl.cc (cxx_init_decl_processing): Declare
	__builtin_source_location with auto return type instead of
	const void*.
	(require_deduced_type): Update the return type of
	__builtin_source_location.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/srcloc3.C: Adjust expected note s/evaluating/using.
	* g++.dg/cpp2a/srcloc4.C: Likewise.
	* g++.dg/cpp2a/srcloc5.C: Likewise.
	* g++.dg/cpp2a/srcloc6.C: Likewise.
	* g++.dg/cpp2a/srcloc7.C: Likewise.
	* g++.dg/cpp2a/srcloc8.C: Likewise.
	* g++.dg/cpp2a/srcloc9.C: Likewise.
	* g++.dg/cpp2a/srcloc10.C: Likewise.
	* g++.dg/cpp2a/srcloc11.C: Likewise.
	* g++.dg/cpp2a/srcloc12.C: Likewise.
	* g++.dg/cpp2a/srcloc13.C: Likewise.
	* g++.dg/modules/pr100881_a.C: New test.
	* g++.dg/modules/pr100881_b.C: New test.
This commit is contained in:
Patrick Palka 2022-12-19 15:35:51 -05:00
parent a7c8036b26
commit 64f7a3b387
17 changed files with 106 additions and 50 deletions

View file

@ -1492,7 +1492,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
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));
return fold_builtin_source_location (t);
}
int strops = 0;

View file

@ -722,7 +722,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
break;
case CP_BUILT_IN_SOURCE_LOCATION:
*expr_p
= fold_builtin_source_location (EXPR_LOCATION (*expr_p));
= fold_builtin_source_location (*expr_p);
break;
case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
*expr_p
@ -2850,7 +2850,7 @@ cp_fold (tree x)
case CP_BUILT_IN_IS_CONSTANT_EVALUATED:
break;
case CP_BUILT_IN_SOURCE_LOCATION:
x = fold_builtin_source_location (EXPR_LOCATION (x));
x = fold_builtin_source_location (x);
break;
case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
x = fold_builtin_is_corresponding_member
@ -2872,7 +2872,7 @@ cp_fold (tree x)
&& fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION,
BUILT_IN_FRONTEND))
{
x = fold_builtin_source_location (EXPR_LOCATION (x));
x = fold_builtin_source_location (x);
break;
}
@ -3171,12 +3171,11 @@ process_stmt_assume_attribute (tree std_attrs, tree statement,
return remove_attribute ("gnu", "assume", std_attrs);
}
/* Helper of fold_builtin_source_location, return the
std::source_location::__impl type after performing verification
on it. LOC is used for reporting any errors. */
/* Return the type std::source_location::__impl after performing
verification on it. */
static tree
get_source_location_impl_type (location_t loc)
tree
get_source_location_impl_type ()
{
tree name = get_identifier ("source_location");
tree decl = lookup_qualified_name (std_node, name);
@ -3184,9 +3183,9 @@ get_source_location_impl_type (location_t loc)
{
auto_diagnostic_group d;
if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
qualified_name_lookup_error (std_node, name, decl, loc);
qualified_name_lookup_error (std_node, name, decl, input_location);
else
error_at (loc, "%qD is not a type", decl);
error ("%qD is not a type", decl);
return error_mark_node;
}
name = get_identifier ("__impl");
@ -3196,15 +3195,15 @@ get_source_location_impl_type (location_t loc)
{
auto_diagnostic_group d;
if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
qualified_name_lookup_error (type, name, decl, loc);
qualified_name_lookup_error (type, name, decl, input_location);
else
error_at (loc, "%qD is not a type", decl);
error ("%qD is not a type", decl);
return error_mark_node;
}
type = TREE_TYPE (decl);
if (TREE_CODE (type) != RECORD_TYPE)
{
error_at (loc, "%qD is not a class type", decl);
error ("%qD is not a class type", decl);
return error_mark_node;
}
@ -3221,8 +3220,7 @@ get_source_location_impl_type (location_t loc)
{
if (TREE_TYPE (field) != const_string_type_node)
{
error_at (loc, "%qD does not have %<const char *%> type",
field);
error ("%qD does not have %<const char *%> type", field);
return error_mark_node;
}
cnt++;
@ -3232,7 +3230,7 @@ get_source_location_impl_type (location_t loc)
{
if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE)
{
error_at (loc, "%qD does not have integral type", field);
error ("%qD does not have integral type", field);
return error_mark_node;
}
cnt++;
@ -3244,9 +3242,9 @@ get_source_location_impl_type (location_t loc)
}
if (cnt != 4)
{
error_at (loc, "%<std::source_location::__impl%> does not contain only "
"non-static data members %<_M_file_name%>, "
"%<_M_function_name%>, %<_M_line%> and %<_M_column%>");
error ("%<std::source_location::__impl%> does not contain only "
"non-static data members %<_M_file_name%>, "
"%<_M_function_name%>, %<_M_line%> and %<_M_column%>");
return error_mark_node;
}
return build_qualified_type (type, TYPE_QUAL_CONST);
@ -3337,21 +3335,20 @@ static GTY(()) hash_table <source_location_table_entry_hash>
*source_location_table;
static GTY(()) unsigned int source_location_id;
/* Fold __builtin_source_location () call. LOC is the location
of the call. */
/* Fold the __builtin_source_location () call T. */
tree
fold_builtin_source_location (location_t loc)
fold_builtin_source_location (const_tree t)
{
if (source_location_impl == NULL_TREE)
{
auto_diagnostic_group d;
source_location_impl = get_source_location_impl_type (loc);
if (source_location_impl == error_mark_node)
inform (loc, "evaluating %qs", "__builtin_source_location");
}
gcc_assert (TREE_CODE (t) == CALL_EXPR);
/* TREE_TYPE (t) is const std::source_location::__impl* */
tree source_location_impl = TREE_TYPE (TREE_TYPE (t));
if (source_location_impl == error_mark_node)
return build_zero_cst (const_ptr_type_node);
gcc_assert (CLASS_TYPE_P (source_location_impl)
&& id_equal (TYPE_IDENTIFIER (source_location_impl), "__impl"));
location_t loc = EXPR_LOCATION (t);
if (source_location_table == NULL)
source_location_table
= hash_table <source_location_table_entry_hash>::create_ggc (64);
@ -3427,7 +3424,7 @@ fold_builtin_source_location (location_t loc)
entryp->var = var;
}
return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node);
return build_fold_addr_expr_with_type_loc (loc, var, TREE_TYPE (t));
}
#include "gt-cp-cp-gimplify.h"

View file

@ -235,8 +235,6 @@ enum cp_tree_index
CPTI_PSEUDO_CONTRACT_VIOLATION,
CPTI_SOURCE_LOCATION_IMPL,
CPTI_FALLBACK_DFLOAT32_TYPE,
CPTI_FALLBACK_DFLOAT64_TYPE,
CPTI_FALLBACK_DFLOAT128_TYPE,
@ -395,9 +393,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
/* A node which matches any template argument. */
#define any_targ_node cp_global_trees[CPTI_ANY_TARG]
/* std::source_location::__impl class. */
#define source_location_impl cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
/* Node to indicate default access. This must be distinct from the
access nodes in tree.h. */
@ -8296,7 +8291,8 @@ extern tree process_stmt_hotness_attribute (tree, location_t);
extern tree build_assume_call (location_t, tree);
extern tree process_stmt_assume_attribute (tree, tree, location_t);
extern bool simple_empty_class_p (tree, tree, tree_code);
extern tree fold_builtin_source_location (location_t);
extern tree fold_builtin_source_location (const_tree);
extern tree get_source_location_impl_type ();
/* in name-lookup.cc */
extern tree strip_using_decl (tree);

View file

@ -4670,9 +4670,13 @@ cxx_init_decl_processing (void)
BUILT_IN_FRONTEND, NULL, NULL_TREE);
set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
tree cptr_ftype = build_function_type_list (const_ptr_type_node, NULL_TREE);
/* The concrete return type of __builtin_source_location is
const std::source_location::__impl*, but we can't form the type
at this point. So we initially declare it with an auto return
type which we then "deduce" from require_deduced_type upon first use. */
tree auto_ftype = build_function_type_list (make_auto (), NULL_TREE);
decl = add_builtin_function ("__builtin_source_location",
cptr_ftype, CP_BUILT_IN_SOURCE_LOCATION,
auto_ftype, CP_BUILT_IN_SOURCE_LOCATION,
BUILT_IN_FRONTEND, NULL, NULL_TREE);
set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
@ -18752,6 +18756,23 @@ require_deduced_type (tree decl, tsubst_flags_t complain)
{
if (undeduced_auto_decl (decl))
{
if (TREE_CODE (decl) == FUNCTION_DECL
&& fndecl_built_in_p (decl, BUILT_IN_FRONTEND)
&& DECL_FE_FUNCTION_CODE (decl) == CP_BUILT_IN_SOURCE_LOCATION)
{
/* Set the return type of __builtin_source_location. */
tree type = get_source_location_impl_type ();
if (type == error_mark_node)
{
inform (input_location, "using %qs", "__builtin_source_location");
return false;
}
type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
type = build_pointer_type (type);
apply_deduced_return_type (decl, type);
return true;
}
if (warning_suppressed_p (decl) && seen_error ())
/* We probably already complained about deduction failure. */;
else if (complain & tf_error)

View file

@ -10,4 +10,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -10,4 +10,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -11,4 +11,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl::_M_file_name' does not have 'const char \\*' type" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -12,4 +12,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl::_M_line' does not have integral type" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -2,4 +2,4 @@
auto x = __builtin_source_location (); // { dg-error "'source_location' is not a member of 'std'" }
// { dg-message "std::source_location' is defined in header '<source_location>'; did you forget to '#include <source_location>'" "" { target *-*-* } .-1 }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-2 }

View file

@ -5,4 +5,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'void std::source_location\\(\\)' is not a type" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -6,4 +6,4 @@ namespace std {
auto x = __builtin_source_location (); // { dg-error "'std::source_location'\[^\n\r]*is not a class type" }
// { dg-error "'__impl' is not a member of 'std::source_location'" "" { target *-*-* } .-1 }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-2 }

View file

@ -6,4 +6,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'__impl' is not a member of 'std::source_location'" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -7,4 +7,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl\\(\\)' is not a type" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -7,4 +7,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl()' is not a class type" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -8,4 +8,4 @@ namespace std {
}
auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }

View file

@ -0,0 +1,34 @@
// PR c++/100881
// { dg-additional-options "-std=c++20 -fmodules-ts" }
// { dg-module-cmi pr100881 }
module;
#include <source_location>
export module pr100881;
export
consteval int
current_line_fn(const std::source_location& loc = std::source_location::current())
{
return loc.line();
}
export
struct current_line_cls
{
int line = std::source_location::current().line();
};
export
template<class T>
consteval int
current_line_fn_tmpl(const std::source_location& loc = std::source_location::current())
{
return loc.line();
}
export
template<class T>
struct current_line_cls_tmpl
{
int line = std::source_location::current().line();
};

View file

@ -0,0 +1,8 @@
// PR c++/100881
// { dg-additional-options "-std=c++20 -fmodules-ts" }
import pr100881;
static_assert(current_line_fn() == 5);
static_assert(current_line_cls{}.line == 6);
static_assert(current_line_fn_tmpl<int>() == 7);
static_assert(current_line_cls_tmpl<int>{}.line == 8);