From: Jakub Jelinek Date: Tue, 3 Dec 2019 23:32:15 +0000 (+0100) Subject: cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ff603745e385a1878a22fa3197911c9c4920a004;p=gcc.git cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL. * cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL. (source_location_impl): Define. (enum cp_built_in_function): Add CP_BUILT_IN_SOURCE_LOCATION. (fold_builtin_source_location): Declare. * cp-gimplify.c: Include output.h, file-prefix-map.h and cgraph.h. (cp_gimplify_expr, cp_fold): Handle CP_BUILT_IN_SOURCE_LOCATION. Formatting fix. (get_source_location_impl_type): New function. (struct source_location_table_entry, struct source_location_table_entry_hash): New types. (source_location_table, source_location_id): New variables. (fold_builtin_source_location): New function. * constexpr.c (cxx_eval_builtin_function_call): Handle CP_BUILT_IN_SOURCE_LOCATION. * tree.c (builtin_valid_in_constant_expr_p): Likewise. Formatting fix. * decl.c (cxx_init_decl_processing): Register __builtin_source_location. * name-lookup.c (get_std_name_hint): Add source_location entry. * g++.dg/cpp2a/srcloc1.C: New test. * g++.dg/cpp2a/srcloc2.C: New test. * g++.dg/cpp2a/srcloc3.C: New test. * g++.dg/cpp2a/srcloc4.C: New test. * g++.dg/cpp2a/srcloc5.C: New test. * g++.dg/cpp2a/srcloc6.C: New test. * g++.dg/cpp2a/srcloc7.C: New test. * g++.dg/cpp2a/srcloc8.C: New test. * g++.dg/cpp2a/srcloc9.C: New test. * g++.dg/cpp2a/srcloc10.C: New test. * g++.dg/cpp2a/srcloc11.C: New test. * g++.dg/cpp2a/srcloc12.C: New test. * g++.dg/cpp2a/srcloc13.C: New test. * g++.dg/cpp2a/srcloc14.C: New test. From-SVN: r278949 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3c86cecfa6e..474a8506e86 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2019-12-03 Jakub Jelinek + + * cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL. + (source_location_impl): Define. + (enum cp_built_in_function): Add CP_BUILT_IN_SOURCE_LOCATION. + (fold_builtin_source_location): Declare. + * cp-gimplify.c: Include output.h, file-prefix-map.h and cgraph.h. + (cp_gimplify_expr, cp_fold): Handle CP_BUILT_IN_SOURCE_LOCATION. + Formatting fix. + (get_source_location_impl_type): New function. + (struct source_location_table_entry, + struct source_location_table_entry_hash): New types. + (source_location_table, source_location_id): New variables. + (fold_builtin_source_location): New function. + * constexpr.c (cxx_eval_builtin_function_call): Handle + CP_BUILT_IN_SOURCE_LOCATION. + * tree.c (builtin_valid_in_constant_expr_p): Likewise. Formatting + fix. + * decl.c (cxx_init_decl_processing): Register + __builtin_source_location. + * name-lookup.c (get_std_name_hint): Add source_location entry. + 2019-12-03 Paolo Carlini * typeck.c (cp_build_addr_expr_1): Use the cp_expr_loc_or_input_loc diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 5afcc876e76..370633467ab 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1240,6 +1240,9 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, return boolean_true_node; } + if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND)) + return fold_builtin_source_location (EXPR_LOCATION (t)); + /* Be permissive for arguments to built-ins; __builtin_constant_p should return constant false for a non-constant argument. */ constexpr_ctx new_ctx = *ctx; diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 7942afa7ece..fb12c8a1420 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -35,6 +35,9 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "asan.h" #include "gcc-rich-location.h" +#include "output.h" +#include "file-prefix-map.h" +#include "cgraph.h" /* Forward declarations. */ @@ -896,8 +899,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) tree decl = cp_get_callee_fndecl_nofold (*expr_p); if (decl && fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND)) + BUILT_IN_FRONTEND)) *expr_p = boolean_false_node; + else if (decl + && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION, + BUILT_IN_FRONTEND)) + *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); } break; @@ -2657,9 +2664,17 @@ cp_fold (tree x) /* Defer folding __builtin_is_constant_evaluated. */ if (callee && fndecl_built_in_p (callee, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND)) + BUILT_IN_FRONTEND)) break; + if (callee + && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION, + BUILT_IN_FRONTEND)) + { + x = fold_builtin_source_location (EXPR_LOCATION (x)); + break; + } + x = copy_node (x); m = call_expr_nargs (x); @@ -2884,4 +2899,246 @@ process_stmt_hotness_attribute (tree std_attrs, location_t attrs_loc) return 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. */ + +static tree +get_source_location_impl_type (location_t loc) +{ + tree name = get_identifier ("source_location"); + tree decl = lookup_qualified_name (std_node, name); + if (TREE_CODE (decl) != TYPE_DECL) + { + auto_diagnostic_group d; + if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST) + qualified_name_lookup_error (std_node, name, decl, loc); + else + error_at (loc, "%qD is not a type", decl); + return error_mark_node; + } + name = get_identifier ("__impl"); + tree type = TREE_TYPE (decl); + decl = lookup_qualified_name (type, name); + if (TREE_CODE (decl) != TYPE_DECL) + { + auto_diagnostic_group d; + if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST) + qualified_name_lookup_error (type, name, decl, loc); + else + error_at (loc, "%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); + return error_mark_node; + } + + int cnt = 0; + for (tree field = TYPE_FIELDS (type); + (field = next_initializable_field (field)) != NULL_TREE; + field = DECL_CHAIN (field)) + { + if (DECL_NAME (field) != NULL_TREE) + { + const char *n = IDENTIFIER_POINTER (DECL_NAME (field)); + if (strcmp (n, "_M_file_name") == 0 + || strcmp (n, "_M_function_name") == 0) + { + if (TREE_TYPE (field) != const_string_type_node) + { + error_at (loc, "%qD does not have % type", + field); + return error_mark_node; + } + cnt++; + continue; + } + else if (strcmp (n, "_M_line") == 0 || strcmp (n, "_M_column") == 0) + { + if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE) + { + error_at (loc, "%qD does not have integral type", field); + return error_mark_node; + } + cnt++; + continue; + } + } + cnt = 0; + break; + } + if (cnt != 4) + { + error_at (loc, "% 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); +} + +/* Type for source_location_table hash_set. */ +struct GTY((for_user)) source_location_table_entry { + location_t loc; + unsigned uid; + tree var; +}; + +/* Traits class for function start hash maps below. */ + +struct source_location_table_entry_hash + : ggc_remove +{ + typedef source_location_table_entry value_type; + typedef source_location_table_entry compare_type; + + static hashval_t + hash (const source_location_table_entry &ref) + { + inchash::hash hstate (0); + hstate.add_int (ref.loc); + hstate.add_int (ref.uid); + return hstate.end (); + } + + static bool + equal (const source_location_table_entry &ref1, + const source_location_table_entry &ref2) + { + return ref1.loc == ref2.loc && ref1.uid == ref2.uid; + } + + static void + mark_deleted (source_location_table_entry &ref) + { + ref.loc = UNKNOWN_LOCATION; + ref.uid = -1U; + ref.var = NULL_TREE; + } + + static void + mark_empty (source_location_table_entry &ref) + { + ref.loc = UNKNOWN_LOCATION; + ref.uid = 0; + ref.var = NULL_TREE; + } + + static bool + is_deleted (const source_location_table_entry &ref) + { + return (ref.loc == UNKNOWN_LOCATION + && ref.uid == -1U + && ref.var == NULL_TREE); + } + + static bool + is_empty (const source_location_table_entry &ref) + { + return (ref.loc == UNKNOWN_LOCATION + && ref.uid == 0 + && ref.var == NULL_TREE); + } +}; + +static GTY(()) hash_table + *source_location_table; +static GTY(()) unsigned int source_location_id; + +/* Fold __builtin_source_location () call. LOC is the location + of the call. */ + +tree +fold_builtin_source_location (location_t loc) +{ + 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"); + } + if (source_location_impl == error_mark_node) + return build_zero_cst (const_ptr_type_node); + if (source_location_table == NULL) + source_location_table + = hash_table ::create_ggc (64); + const line_map_ordinary *map; + source_location_table_entry entry; + entry.loc + = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT, + &map); + entry.uid = current_function_decl ? DECL_UID (current_function_decl) : -1; + entry.var = error_mark_node; + source_location_table_entry *entryp + = source_location_table->find_slot (entry, INSERT); + tree var; + if (entryp->var) + var = entryp->var; + else + { + char tmp_name[32]; + ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++); + var = build_decl (loc, VAR_DECL, get_identifier (tmp_name), + source_location_impl); + TREE_STATIC (var) = 1; + TREE_PUBLIC (var) = 0; + DECL_ARTIFICIAL (var) = 1; + DECL_IGNORED_P (var) = 1; + DECL_EXTERNAL (var) = 0; + DECL_DECLARED_CONSTEXPR_P (var) = 1; + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = 1; + layout_decl (var, 0); + + vec *v = NULL; + vec_alloc (v, 4); + for (tree field = TYPE_FIELDS (source_location_impl); + (field = next_initializable_field (field)) != NULL_TREE; + field = DECL_CHAIN (field)) + { + const char *n = IDENTIFIER_POINTER (DECL_NAME (field)); + tree val = NULL_TREE; + if (strcmp (n, "_M_file_name") == 0) + { + if (const char *fname = LOCATION_FILE (loc)) + { + fname = remap_macro_filename (fname); + val = build_string_literal (strlen (fname) + 1, fname); + } + else + val = build_string_literal (1, ""); + } + else if (strcmp (n, "_M_function_name") == 0) + { + const char *name = ""; + + if (current_function_decl) + name = cxx_printable_name (current_function_decl, 0); + + val = build_string_literal (strlen (name) + 1, name); + } + else if (strcmp (n, "_M_line") == 0) + val = build_int_cst (TREE_TYPE (field), LOCATION_LINE (loc)); + else if (strcmp (n, "_M_column") == 0) + val = build_int_cst (TREE_TYPE (field), LOCATION_COLUMN (loc)); + else + gcc_unreachable (); + CONSTRUCTOR_APPEND_ELT (v, field, val); + } + + tree ctor = build_constructor (source_location_impl, v); + TREE_CONSTANT (ctor) = 1; + TREE_STATIC (ctor) = 1; + DECL_INITIAL (var) = ctor; + varpool_node::finalize_decl (var); + *entryp = entry; + entryp->var = var; + } + + return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node); +} + #include "gt-cp-cp-gimplify.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4af18b0ae62..666894ff882 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -204,6 +204,8 @@ enum cp_tree_index CPTI_ANY_TARG, + CPTI_SOURCE_LOCATION_IMPL, + CPTI_MAX }; @@ -356,6 +358,9 @@ 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. */ @@ -6182,6 +6187,7 @@ struct GTY((chain_next ("%h.next"))) tinst_level { enum cp_built_in_function { CP_BUILT_IN_IS_CONSTANT_EVALUATED, CP_BUILT_IN_INTEGER_PACK, + CP_BUILT_IN_SOURCE_LOCATION, CP_BUILT_IN_LAST }; @@ -7735,6 +7741,7 @@ extern void clear_fold_cache (void); extern tree lookup_hotness_attribute (tree); extern tree process_stmt_hotness_attribute (tree, location_t); extern bool simple_empty_class_p (tree, tree, tree_code); +extern tree fold_builtin_source_location (location_t); /* in name-lookup.c */ extern tree strip_using_decl (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 54f09507516..481c798a2cf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4290,6 +4290,12 @@ 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); + decl = add_builtin_function ("__builtin_source_location", + cptr_ftype, CP_BUILT_IN_SOURCE_LOCATION, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + integer_two_node = build_int_cst (NULL_TREE, 2); /* Guess at the initial static decls size. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index a298b61bda9..e82eaf222c0 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5747,6 +5747,8 @@ get_std_name_hint (const char *name) {"shared_lock", "", cxx14}, {"shared_mutex", "", cxx17}, {"shared_timed_mutex", "", cxx14}, + /* . */ + {"source_location", "", cxx2a}, /* . */ {"basic_stringbuf", "", cxx98}, {"basic_istringstream", "", cxx98}, diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 620e2c2699c..57745543163 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -445,7 +445,9 @@ builtin_valid_in_constant_expr_p (const_tree decl) if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL) { if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND)) + BUILT_IN_FRONTEND) + || fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION, + BUILT_IN_FRONTEND)) return true; /* Not a built-in. */ return false; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 330b75b4ff0..8ae30c286a7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2019-12-03 Jakub Jelinek + + * g++.dg/cpp2a/srcloc1.C: New test. + * g++.dg/cpp2a/srcloc2.C: New test. + * g++.dg/cpp2a/srcloc3.C: New test. + * g++.dg/cpp2a/srcloc4.C: New test. + * g++.dg/cpp2a/srcloc5.C: New test. + * g++.dg/cpp2a/srcloc6.C: New test. + * g++.dg/cpp2a/srcloc7.C: New test. + * g++.dg/cpp2a/srcloc8.C: New test. + * g++.dg/cpp2a/srcloc9.C: New test. + * g++.dg/cpp2a/srcloc10.C: New test. + * g++.dg/cpp2a/srcloc11.C: New test. + * g++.dg/cpp2a/srcloc12.C: New test. + * g++.dg/cpp2a/srcloc13.C: New test. + * g++.dg/cpp2a/srcloc14.C: New test. + 2019-12-03 Paolo Carlini * g++.dg/diagnostic/inconsistent-deduction-1.C: New. diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc1.C b/gcc/testsuite/g++.dg/cpp2a/srcloc1.C new file mode 100644 index 00000000000..c88bc146a5d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc1.C @@ -0,0 +1,114 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + const char *_M_file_name; + const char *_M_function_name; + unsigned int _M_line, _M_column; + }; + const __impl *__ptr; + constexpr source_location () : __ptr (nullptr) {} + static consteval source_location + current (const void *__p = __builtin_source_location ()) { + source_location __ret; + __ret.__ptr = static_cast (__p); + return __ret; + } + constexpr const char *file_name () const { + return __ptr ? __ptr->_M_file_name : ""; + } + constexpr const char *function_name () const { + return __ptr ? __ptr->_M_function_name : ""; + } + constexpr unsigned line () const { + return __ptr ? __ptr->_M_line : 0; + } + constexpr unsigned column () const { + return __ptr ? __ptr->_M_column : 0; + } + }; +} + +using namespace std; + +consteval source_location +bar (const source_location x = source_location::current ()) +{ + return x; +} + +void +foo (const char **p, unsigned *q) +{ + constexpr source_location s = source_location::current (); + constexpr source_location t = bar (); + p[0] = s.file_name (); + p[1] = s.function_name (); + q[0] = s.line (); + q[1] = s.column (); + p[2] = t.file_name (); + p[3] = t.function_name (); + q[2] = t.line (); + q[3] = t.column (); + constexpr const char *r = s.file_name (); +} + +source_location s3 = source_location::current (); + +template +constexpr source_location +baz () +{ + return source_location::current (); +} + +#define A \ + source_location s[3] = { source_location::current (), \ + source_location::current (), \ + source_location::current () } + +source_location * +boo () +{ + static A; + return &s[0]; +} + +constexpr source_location s1 = baz <0> (); +constexpr source_location s2 = baz <1> (); +const source_location *p1 = &s1; +const source_location *p2 = &s2; +static_assert (source_location::current ().line () == __LINE__); +static_assert (source_location::current ().column () == 42); + +constexpr bool +quux () +{ + const char *file1 = source_location::current ().file_name (); + const char *file2 = __FILE__; + const char *function1 = source_location::current ().function_name (); + const char *function2 = __FUNCTION__; + int line1 = source_location::current ().line (); + int line2 = __LINE__ - 1; + int column + = source_location::current ().column (); + int i = 0; + for (; file1[i]; i++) + if (file1[i] != file2[i]) + return false; + if (file2[i]) + return false; + for (i = 0; function1[i]; i++) + if (function1[i] != function2[i]) + return false; + if (function2[i]) + return false; + if (line1 != line2) + return false; + if (column != 33) + return false; + return true; +} + +static_assert (quux ()); diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc10.C b/gcc/testsuite/g++.dg/cpp2a/srcloc10.C new file mode 100644 index 00000000000..a27016d1e36 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc10.C @@ -0,0 +1,13 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + const char *_M_file_name, *_M_function_name; + int __foo, _M_line, _M_column; + }; + }; +} + +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 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc11.C b/gcc/testsuite/g++.dg/cpp2a/srcloc11.C new file mode 100644 index 00000000000..742a8925e54 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc11.C @@ -0,0 +1,13 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + const char *_M_file_name, *_M_function_name; + int _M_line; + }; + }; +} + +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 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc12.C b/gcc/testsuite/g++.dg/cpp2a/srcloc12.C new file mode 100644 index 00000000000..900e5a8cab8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc12.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + const void *_M_file_name; + const char *_M_function_name; + int _M_line, _M_column; + }; + }; +} + +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 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc13.C b/gcc/testsuite/g++.dg/cpp2a/srcloc13.C new file mode 100644 index 00000000000..890931236b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc13.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + const char *_M_file_name; + const char *_M_function_name; + float _M_line; + int _M_column; + }; + }; +} + +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 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc14.C b/gcc/testsuite/g++.dg/cpp2a/srcloc14.C new file mode 100644 index 00000000000..21ab8311d36 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc14.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + // Test that ordering doesn't matter + long long _M_column; + const char *_M_file_name; + int _M_line; + const char *_M_function_name; + }; + }; +} + +auto x = __builtin_source_location (); diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc2.C b/gcc/testsuite/g++.dg/cpp2a/srcloc2.C new file mode 100644 index 00000000000..380d83428cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc2.C @@ -0,0 +1,118 @@ +// { dg-do compile { target c++2a } } + +namespace std { + inline namespace _8 { } + namespace _8 { + struct source_location { + struct __impl { + const char *_M_file_name; + const char *_M_function_name; + unsigned int _M_line, _M_column; + }; + const __impl *__ptr; + constexpr source_location () : __ptr (nullptr) {} + static consteval source_location + current (const void *__p = __builtin_source_location ()) { + source_location __ret; + __ret.__ptr = static_cast (__p); + return __ret; + } + constexpr const char *file_name () const { + return __ptr ? __ptr->_M_file_name : ""; + } + constexpr const char *function_name () const { + return __ptr ? __ptr->_M_function_name : ""; + } + constexpr unsigned line () const { + return __ptr ? __ptr->_M_line : 0; + } + constexpr unsigned column () const { + return __ptr ? __ptr->_M_column : 0; + } + }; + } +} + +using namespace std; + +consteval source_location +bar (const source_location x = source_location::current ()) +{ + return x; +} + +void +foo (const char **p, unsigned *q) +{ + constexpr source_location s = source_location::current (); + constexpr source_location t = bar (); + p[0] = s.file_name (); + p[1] = s.function_name (); + q[0] = s.line (); + q[1] = s.column (); + p[2] = t.file_name (); + p[3] = t.function_name (); + q[2] = t.line (); + q[3] = t.column (); + constexpr const char *r = s.file_name (); +} + +source_location s3 = source_location::current (); + +template +constexpr source_location +baz () +{ + return source_location::current (); +} + +#define A \ + source_location s[3] = { source_location::current (), \ + source_location::current (), \ + source_location::current () } + +source_location * +boo () +{ + static A; + return &s[0]; +} + +constexpr source_location s1 = baz <0> (); +constexpr source_location s2 = baz <1> (); +const source_location *p1 = &s1; +const source_location *p2 = &s2; + +static_assert (source_location::current ().line () == __LINE__); +static_assert (source_location::current ().column () == 42); + +constexpr bool +quux () +{ + const char *file1 = source_location::current ().file_name (); + const char *file2 = __FILE__; + const char *function1 = source_location::current ().function_name (); + const char *function2 = __FUNCTION__; + int line1 = source_location::current ().line (); + int line2 = __LINE__ - 1; + int column + = source_location::current ().column (); + int i = 0; + for (; file1[i]; i++) + if (file1[i] != file2[i]) + return false; + if (file2[i]) + return false; + for (i = 0; function1[i]; i++) + if (function1[i] != function2[i]) + return false; + if (function2[i]) + return false; + if (line1 != line2) + return false; + if (column != 33) + return false; + return true; +} + +static_assert (quux ()); diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc3.C b/gcc/testsuite/g++.dg/cpp2a/srcloc3.C new file mode 100644 index 00000000000..b841ff6ceaa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc3.C @@ -0,0 +1,5 @@ +// { dg-do compile { target c++2a } } + +auto x = __builtin_source_location (); // { dg-error "'source_location' is not a member of 'std'" } +// { dg-message "std::source_location' is defined in header ''; did you forget to '#include '" "" { target *-*-* } .-1 } +// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc4.C b/gcc/testsuite/g++.dg/cpp2a/srcloc4.C new file mode 100644 index 00000000000..c8c5f513931 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc4.C @@ -0,0 +1,8 @@ +// { dg-do compile { target c++2a } } + +namespace std { + void source_location (); +} + +auto x = __builtin_source_location (); // { dg-error "'void std::source_location\\(\\)' is not a type" } +// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc5.C b/gcc/testsuite/g++.dg/cpp2a/srcloc5.C new file mode 100644 index 00000000000..0e89a00a13c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc5.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++2a } } + +namespace std { + typedef int source_location; +} + +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 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc6.C b/gcc/testsuite/g++.dg/cpp2a/srcloc6.C new file mode 100644 index 00000000000..a389add2e7c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc6.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + }; +} + +auto x = __builtin_source_location (); // { dg-error "'__impl' is not a member of 'std::source_location'" } +// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc7.C b/gcc/testsuite/g++.dg/cpp2a/srcloc7.C new file mode 100644 index 00000000000..2a8b569a1af --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc7.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + static void __impl (); + }; +} + +auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl\\(\\)' is not a type" } +// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc8.C b/gcc/testsuite/g++.dg/cpp2a/srcloc8.C new file mode 100644 index 00000000000..db56bb5ff90 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc8.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + typedef int __impl; + }; +} + +auto x = __builtin_source_location (); // { dg-error "'std::source_location::__impl()' is not a class type" } +// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc9.C b/gcc/testsuite/g++.dg/cpp2a/srcloc9.C new file mode 100644 index 00000000000..01ba00aaf41 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc9.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++2a } } + +namespace std { + struct source_location { + struct __impl { + }; + }; +} + +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 }