* 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
+2019-12-03 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <paolo.carlini@oracle.com>
* typeck.c (cp_build_addr_expr_1): Use the cp_expr_loc_or_input_loc
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;
#include "attribs.h"
#include "asan.h"
#include "gcc-rich-location.h"
+#include "output.h"
+#include "file-prefix-map.h"
+#include "cgraph.h"
/* Forward declarations. */
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;
/* 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);
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 %<const char *%> 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, "%<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);
+}
+
+/* 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 <source_location_table_entry>
+{
+ 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_entry_hash>
+ *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 <source_location_table_entry_hash>::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<constructor_elt, va_gc> *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"
CPTI_ANY_TARG,
+ CPTI_SOURCE_LOCATION_IMPL,
+
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. */
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
};
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);
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. */
{"shared_lock", "<shared_mutex>", cxx14},
{"shared_mutex", "<shared_mutex>", cxx17},
{"shared_timed_mutex", "<shared_mutex>", cxx14},
+ /* <source_location>. */
+ {"source_location", "<source_location>", cxx2a},
/* <sstream>. */
{"basic_stringbuf", "<sstream>", cxx98},
{"basic_istringstream", "<sstream>", cxx98},
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;
+2019-12-03 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <paolo.carlini@oracle.com>
* g++.dg/diagnostic/inconsistent-deduction-1.C: New.
--- /dev/null
+// { 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 <const __impl *> (__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 <int N>
+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 ());
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 ();
--- /dev/null
+// { 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 <const __impl *> (__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 <int N>
+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 ());
--- /dev/null
+// { 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 '<source_location>'; did you forget to '#include <source_location>'" "" { target *-*-* } .-1 }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }
--- /dev/null
+// { 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 }