llvm-project/clang/test/SemaCXX/source_location.cpp
Matheus Izvekov 7fd02b32f9
[clang] NFC: Add test case for #178324 and mark it as fixed (#190490)
Issue #178324 was actually fixed by #187755

We lost the "declaration does not declare anything" warning since the
regression was introduced, but that was because:
1) Since #78436 we treat __builtin_FUNCSIG in a dependent context
effectivelly as if it contained a template parameter.
2) Our decltype implementation treats eexpressions containing template
parameters as if they were completely opaque (but alas this goes against
the spec, which says in [temp.type]p4 this should be looking only at
type dependence).
3) Since the decltype is opaque, we don't know what lookup will find, so
we can't issue the warning because we don't know if we are going to end
up with a type or an expression.

Fixes #178324
2026-04-04 19:10:29 -03:00

1094 lines
30 KiB
C++

// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -verify %s
// RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -verify %s
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fms-compatibility -verify %s
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fms-compatibility -verify %s
//
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
// RUN: %clang_cc1 -std=c++2b -fcxx-exceptions -DUSE_CONSTEVAL -DPAREN_INIT -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fms-extensions -DMS -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -fms-compatibility -verify %s
// RUN: %clang_cc1 -std=c++2a -fcxx-exceptions -fms-extensions -DMS -DUSE_CONSTEVAL -fexceptions -fexperimental-new-constant-interpreter -DNEW_INTERP -verify -fms-compatibility %s
// expected-no-diagnostics
#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
#define CURRENT_FROM_MACRO() SL::current()
#define FORWARD(...) __VA_ARGS__
template <unsigned>
struct Printer;
#ifdef USE_CONSTEVAL
#define SOURCE_LOC_EVAL_KIND consteval
#else
#define SOURCE_LOC_EVAL_KIND constexpr
#endif
namespace std {
class source_location {
struct __impl;
public:
static SOURCE_LOC_EVAL_KIND source_location
current(const __impl *__p = __builtin_source_location()) noexcept {
source_location __loc;
__loc.__m_impl = __p;
return __loc;
}
constexpr source_location() = default;
constexpr source_location(source_location const &) = default;
constexpr unsigned int line() const noexcept { return __m_impl ? __m_impl->_M_line : 0; }
constexpr unsigned int column() const noexcept { return __m_impl ? __m_impl->_M_column : 0; }
constexpr const char *file() const noexcept { return __m_impl ? __m_impl->_M_file_name : ""; }
constexpr const char *function() const noexcept { return __m_impl ? __m_impl->_M_function_name : ""; }
private:
// Note: The type name "std::source_location::__impl", and its constituent
// field-names are required by __builtin_source_location().
struct __impl {
const char *_M_file_name;
const char *_M_function_name;
unsigned _M_line;
unsigned _M_column;
};
const __impl *__m_impl = nullptr;
public:
using public_impl_alias = __impl;
};
} // namespace std
using SL = std::source_location;
#include "Inputs/source-location-file.h"
namespace SLF = source_location_file;
constexpr bool is_equal(const char *LHS, const char *RHS) {
while (*LHS != 0 && *RHS != 0) {
if (*LHS != *RHS)
return false;
++LHS;
++RHS;
}
return *LHS == 0 && *RHS == 0;
}
template <class T>
constexpr T identity(T t) {
return t;
}
template <class T, class U>
struct Pair {
T first;
U second;
};
template <class T, class U>
constexpr bool is_same = false;
template <class T>
constexpr bool is_same<T, T> = true;
// test types
static_assert(is_same<decltype(__builtin_LINE()), unsigned>);
static_assert(is_same<decltype(__builtin_COLUMN()), unsigned>);
static_assert(is_same<decltype(__builtin_FILE()), const char *>);
static_assert(is_same<decltype(__builtin_FILE_NAME()), const char *>);
static_assert(is_same<decltype(__builtin_FUNCTION()), const char *>);
#ifdef MS
static_assert(is_same<decltype(__builtin_FUNCSIG()), const char *>);
#endif
static_assert(is_same<decltype(__builtin_source_location()), const std::source_location::public_impl_alias *>);
// test noexcept
static_assert(noexcept(__builtin_LINE()));
static_assert(noexcept(__builtin_COLUMN()));
static_assert(noexcept(__builtin_FILE()));
static_assert(noexcept(__builtin_FILE_NAME()));
static_assert(noexcept(__builtin_FUNCTION()));
#ifdef MS
static_assert(noexcept(__builtin_FUNCSIG()));
#endif
static_assert(noexcept(__builtin_source_location()));
//===----------------------------------------------------------------------===//
// __builtin_LINE()
//===----------------------------------------------------------------------===//
namespace test_line {
static_assert(SL::current().line() == __LINE__);
static_assert(SL::current().line() == CURRENT_FROM_MACRO().line());
static constexpr SL GlobalS = SL::current();
static_assert(GlobalS.line() == __LINE__ - 2);
// clang-format off
constexpr bool test_line_fn() {
constexpr SL S = SL::current();
static_assert(S.line() == (__LINE__ - 1), "");
// The start of the call expression to `current()` begins at the token `SL`
constexpr int ExpectLine = __LINE__ + 3;
constexpr SL S2
=
SL // Call expression starts here
::
current
(
)
;
static_assert(S2.line() == ExpectLine, "");
static_assert(
FORWARD(
__builtin_LINE
(
)
)
== __LINE__ - 1, "");
static_assert(\
\
__builtin_LINE()\
\
== __LINE__ - 2, "");
static_assert(\
_\
_builtin_LINE()
== __LINE__ - 2, "");
return true;
}
// clang-format on
static_assert(test_line_fn());
static_assert(__builtin_LINE() == __LINE__, "");
constexpr int baz() { return 101; }
constexpr int test_line_fn_simple(int z = baz(), int x = __builtin_LINE()) {
return x;
}
void bar() {
static_assert(test_line_fn_simple() == __LINE__, "");
static_assert(test_line_fn_simple() == __LINE__, "");
}
struct CallExpr {
constexpr int operator()(int x = __builtin_LINE()) const { return x; }
};
constexpr CallExpr get_call() { return CallExpr{}; }
static_assert(get_call()() == __LINE__, "");
template <class T>
constexpr bool test_line_fn_template(T Expect, int L = __builtin_LINE()) {
return Expect == L;
}
static_assert(test_line_fn_template(__LINE__));
struct InMemInit {
constexpr bool check(int expect) const {
return info.line() == expect;
}
SL info = SL::current();
InMemInit() = default;
constexpr InMemInit(int) {}
};
static_assert(InMemInit{}.check(__LINE__ - 3), "");
static_assert(InMemInit{42}.check(__LINE__ - 3), "");
template <class T, class U = SL>
struct InMemInitTemplate {
constexpr bool check(int expect) const {
return info.line() == expect;
}
U info = U::current();
InMemInitTemplate() = default;
constexpr InMemInitTemplate(T) {}
constexpr InMemInitTemplate(T, T) : info(U::current()) {}
template <class V = U> constexpr InMemInitTemplate(T, T, T, V info = U::current())
: info(info) {}
};
void test_mem_init_template() {
constexpr int line_offset = 8;
static_assert(InMemInitTemplate<int>{}.check(__LINE__ - line_offset), "");
static_assert(InMemInitTemplate<unsigned>{42}.check(__LINE__ - line_offset), "");
static_assert(InMemInitTemplate<unsigned>{42, 42}.check(__LINE__ - line_offset), "");
static_assert(InMemInitTemplate<unsigned>{42, 42, 42}.check(__LINE__), "");
}
struct AggInit {
int x;
int y = __builtin_LINE();
constexpr bool check(int expect) const {
return y == expect;
}
};
constexpr AggInit AI{42};
static_assert(AI.check(__LINE__ - 1), "");
template <class T, class U = SL>
struct AggInitTemplate {
constexpr bool check(int expect) const {
return expect == info.line();
}
T x;
U info = U::current();
};
template <class T, class U = SL>
constexpr U test_fn_template(T, U u = U::current()) {
return u;
}
void fn_template_tests() {
static_assert(test_fn_template(42).line() == __LINE__, "");
}
struct TestMethodTemplate {
template <class T, class U = SL, class U2 = SL>
constexpr U get(T, U u = U::current(), U2 u2 = identity(U2::current())) const {
assert(u.line() == u2.line());
return u;
}
};
void method_template_tests() {
static_assert(TestMethodTemplate{}.get(42).line() == __LINE__, "");
}
struct InStaticInit {
static constexpr int LINE = __LINE__;
static constexpr const int x1 = __builtin_LINE();
static constexpr const int x2 = identity(__builtin_LINE());
static const int x3;
const int x4 = __builtin_LINE();
int x5 = __builtin_LINE();
};
const int InStaticInit::x3 = __builtin_LINE();
static_assert(InStaticInit::x1 == InStaticInit::LINE + 1, "");
static_assert(InStaticInit::x2 == InStaticInit::LINE + 2, "");
template <class T, int N = __builtin_LINE(), int Expect = -1>
constexpr void check_fn_template_param(T) {
constexpr int RealExpect = Expect == -1 ? __LINE__ - 2 : Expect;
static_assert(N == RealExpect);
}
template void check_fn_template_param(int);
template void check_fn_template_param<long, 42, 42>(long);
#line 100
struct AggBase {
#line 200
int x = __builtin_LINE();
int y = __builtin_LINE();
int z = __builtin_LINE();
};
#line 300
struct AggDer : AggBase {
};
#line 400
static_assert(AggDer{}.x == 400, "");
struct ClassBase {
#line 400
int x = __builtin_LINE();
int y = 0;
int z = 0;
#line 500
ClassBase() = default;
constexpr ClassBase(int yy, int zz = __builtin_LINE())
: y(yy), z(zz) {}
};
struct ClassDer : ClassBase {
#line 600
ClassDer() = default;
constexpr ClassDer(int yy) : ClassBase(yy) {}
constexpr ClassDer(int yy, int zz) : ClassBase(yy, zz) {}
};
#line 700
static_assert(ClassDer{}.x == 500, "");
static_assert(ClassDer{42}.x == 501, "");
static_assert(ClassDer{42}.z == 601, "");
static_assert(ClassDer{42, 42}.x == 501, "");
struct ClassAggDer : AggBase {
#line 800
ClassAggDer() = default;
constexpr ClassAggDer(int, int x = __builtin_LINE()) : AggBase{x} {}
};
static_assert(ClassAggDer{}.x == 100, "");
} // namespace test_line
//===----------------------------------------------------------------------===//
// __builtin_FILE()
//===----------------------------------------------------------------------===//
namespace test_file {
constexpr const char *test_file_simple(const char *__f = __builtin_FILE()) {
return __f;
}
void test_function() {
#line 900
static_assert(is_equal(test_file_simple(), __FILE__));
static_assert(is_equal(SLF::test_function().file(), __FILE__), "");
static_assert(is_equal(SLF::test_function_template(42).file(), __FILE__), "");
static_assert(is_equal(SLF::test_function_indirect().file(), SLF::global_info.file()), "");
static_assert(is_equal(SLF::test_function_template_indirect(42).file(), SLF::global_info.file()), "");
static_assert(test_file_simple() != nullptr);
static_assert(!is_equal(test_file_simple(), "source_location.cpp"));
}
void test_class() {
#line 315
using SLF::TestClass;
constexpr TestClass Default;
constexpr TestClass InParam{42};
constexpr TestClass Template{42, 42};
constexpr auto *F = Default.info.file();
constexpr auto Char = F[0];
static_assert(is_equal(Default.info.file(), SLF::FILE), "");
static_assert(is_equal(InParam.info.file(), SLF::FILE), "");
static_assert(is_equal(InParam.ctor_info.file(), __FILE__), "");
}
void test_aggr_class() {
using Agg = SLF::AggrClass<>;
constexpr Agg Default{};
constexpr Agg InitOne{42};
static_assert(is_equal(Default.init_info.file(), __FILE__), "");
static_assert(is_equal(InitOne.init_info.file(), __FILE__), "");
}
} // namespace test_file
//===----------------------------------------------------------------------===//
// __builtin_FILE_NAME()
//===----------------------------------------------------------------------===//
namespace test_file_name {
constexpr const char *test_file_name_simple(
const char *__f = __builtin_FILE_NAME()) {
return __f;
}
void test_function() {
#line 900
static_assert(is_equal(test_file_name_simple(), __FILE_NAME__));
static_assert(is_equal(SLF::test_function_filename(), __FILE_NAME__), "");
static_assert(is_equal(SLF::test_function_filename_template(42),
__FILE_NAME__), "");
static_assert(is_equal(SLF::test_function_filename_indirect(),
SLF::global_info_filename), "");
static_assert(is_equal(SLF::test_function_filename_template_indirect(42),
SLF::global_info_filename), "");
static_assert(test_file_name_simple() != nullptr);
static_assert(is_equal(test_file_name_simple(), "source_location.cpp"));
}
void test_class() {
#line 315
using SLF::TestClass;
constexpr TestClass Default;
constexpr TestClass InParam{42};
constexpr TestClass Template{42, 42};
constexpr auto *F = Default.info_file_name;
constexpr auto Char = F[0];
static_assert(is_equal(Default.info_file_name, SLF::FILE_NAME), "");
static_assert(is_equal(InParam.info_file_name, SLF::FILE_NAME), "");
static_assert(is_equal(InParam.ctor_info_file_name, __FILE_NAME__), "");
}
void test_aggr_class() {
using Agg = SLF::AggrClass<>;
constexpr Agg Default{};
constexpr Agg InitOne{42};
static_assert(is_equal(Default.init_info_file_name, __FILE_NAME__), "");
static_assert(is_equal(InitOne.init_info_file_name, __FILE_NAME__), "");
}
} // namespace test_file_name
//===----------------------------------------------------------------------===//
// __builtin_FUNCTION()
//===----------------------------------------------------------------------===//
namespace test_func {
constexpr const char *test_func_simple(const char *__f = __builtin_FUNCTION()) {
return __f;
}
constexpr const char *get_function() {
return __func__;
}
constexpr bool test_function() {
return is_equal(__func__, test_func_simple()) &&
!is_equal(get_function(), test_func_simple());
}
static_assert(test_function());
template <class T, class U = SL>
constexpr Pair<U, U> test_func_template(T, U u = U::current()) {
static_assert(is_equal(__PRETTY_FUNCTION__, U::current().function()));
return {u, U::current()};
}
template <class T>
void func_template_tests() {
constexpr auto P = test_func_template(42);
//static_assert(is_equal(P.first.function(), __func__), "");
//static_assert(!is_equal(P.second.function(), __func__), "");
}
template void func_template_tests<int>();
template <class = int, class T = SL>
struct TestCtor {
T info = T::current();
T ctor_info;
TestCtor() = default;
template <class U = SL>
constexpr TestCtor(int, U u = U::current()) : ctor_info(u) {}
};
void ctor_tests() {
constexpr TestCtor<> Default;
constexpr TestCtor<> Template{42};
static const char *XYZZY = Template.info.function();
static_assert(is_equal(Default.info.function(), "test_func::TestCtor<>::TestCtor() [T = std::source_location]"));
static_assert(is_equal(Default.ctor_info.function(), ""));
static_assert(is_equal(Template.info.function(), "test_func::TestCtor<>::TestCtor(int, U) [T = std::source_location, U = std::source_location]"));
static_assert(is_equal(Template.ctor_info.function(), __PRETTY_FUNCTION__));
}
constexpr SL global_sl = SL::current();
static_assert(is_equal(global_sl.function(), ""));
template <class T>
class TestBI {
public:
TestBI() {
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::TestBI<int>::TestBI"));
#else
static_assert(is_equal(__FUNCTION__, "TestBI"));
#endif
static_assert(is_equal(__func__, "TestBI"));
}
};
template <class T>
class TestClass {
public:
TestClass() {
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::TestClass<class test_func::C>::TestClass"));
#else
static_assert(is_equal(__FUNCTION__, "TestClass"));
#endif
static_assert(is_equal(__func__, "TestClass"));
}
};
template <class T>
class TestStruct {
public:
TestStruct() {
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::TestStruct<struct test_func::S>::TestStruct"));
#else
static_assert(is_equal(__FUNCTION__, "TestStruct"));
#endif
static_assert(is_equal(__func__, "TestStruct"));
}
};
template <class T>
class TestEnum {
public:
TestEnum() {
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::TestEnum<enum test_func::E>::TestEnum"));
#else
static_assert(is_equal(__FUNCTION__, "TestEnum"));
#endif
static_assert(is_equal(__func__, "TestEnum"));
}
};
class C {};
struct S {};
enum E {};
TestBI<int> t1;
TestClass<test_func::C> t2;
TestStruct<test_func::S> t3;
TestEnum<test_func::E> t4;
class A { int b;};
namespace inner {
template <class Ty>
class C {
public:
template <class T>
static void f(int i) {
(void)i;
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::inner::C<class test_func::A>::f"));
#else
static_assert(is_equal(__FUNCTION__, "f"));
#endif
}
template <class T>
static constexpr void cf(int i) {
(void)i;
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::inner::C<class test_func::A>::cf"));
#else
static_assert(is_equal(__FUNCTION__, "cf"));
#endif
}
template <class T>
static void df(double f) {
(void)f;
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::inner::C<class test_func::A>::df"));
#else
static_assert(is_equal(__FUNCTION__, "df"));
#endif
}
template <class T>
static constexpr void cdf(double f) {
(void)f;
#ifdef MS
static_assert(is_equal(__FUNCTION__, "test_func::inner::C<class test_func::A>::cdf"));
#else
static_assert(is_equal(__FUNCTION__, "cdf"));
#endif
}
};
}
void foo() {
test_func::inner::C<test_func::A>::f<char>(1);
test_func::inner::C<test_func::A>::cf<char>(1);
test_func::inner::C<test_func::A>::df<void>(1.0);
test_func::inner::C<test_func::A>::cdf<void>(1.0);
}
} // namespace test_func
//===----------------------------------------------------------------------===//
// __builtin_FUNCSIG()
//===----------------------------------------------------------------------===//
#ifdef MS
namespace test_funcsig {
constexpr const char *test_funcsig_simple(const char *f = __builtin_FUNCSIG()) {
return f;
}
constexpr const char *get_funcsig() {
return __FUNCSIG__;
}
constexpr bool test_funcsig() {
return is_equal(__FUNCSIG__, test_funcsig_simple()) &&
!is_equal(get_funcsig(), test_funcsig_simple());
}
static_assert(test_funcsig());
template <class T>
constexpr Pair<const char*, const char*> test_funcsig_template(T, const char* f = __builtin_FUNCSIG()) {
return {f, __builtin_FUNCSIG()};
}
template <class T>
void func_template_tests() {
constexpr auto P = test_funcsig_template(42);
static_assert(is_equal(P.first, __FUNCSIG__), "");
static_assert(!is_equal(P.second, __FUNCSIG__), "");
}
template void func_template_tests<int>();
template <class = int, class T = const char*>
struct TestCtor {
T funcsig = __builtin_FUNCSIG();
T ctor_funcsig;
TestCtor() = default;
template <class F = const char*>
constexpr TestCtor(int, F f = __builtin_FUNCSIG()) : ctor_funcsig(f) {}
};
void ctor_tests() {
constexpr TestCtor<> Template{42};
static_assert(is_equal(Template.funcsig, "__cdecl test_funcsig::TestCtor<>::TestCtor(int, F) [T = const char *, F = const char *]"));
static_assert(is_equal(Template.ctor_funcsig, __FUNCSIG__));
}
constexpr const char* global_funcsig = __builtin_FUNCSIG();
static_assert(is_equal(global_funcsig, ""));
} // namespace test_funcsig
#endif
//===----------------------------------------------------------------------===//
// __builtin_COLUMN()
//===----------------------------------------------------------------------===//
namespace test_column {
// clang-format off
constexpr bool test_column_fn() {
constexpr SL S = SL::current();
static_assert(S.line() == (__LINE__ - 1), "");
constexpr int Indent = 4;
{
// The start of the call expression to `current()` begins at the token `SL`
constexpr int ExpectCol = Indent + 3;
constexpr SL S2
=
SL // Call expression starts here
::
current
(
)
;
static_assert(S2.column() == ExpectCol, "");
}
{
constexpr int ExpectCol = 2;
constexpr int C =
__builtin_COLUMN // Expect call expression to start here
();
static_assert(C == ExpectCol);
}
return true;
}
#line 420
static_assert(test_column_fn());
// Test that the column matches the start of the call expression 'SL::current()'
static_assert(SL::current().column() == __builtin_strlen("static_assert(S"));
struct TestClass {
int x = __builtin_COLUMN();
TestClass() = default; /* indented to 3 spaces for testing */
constexpr TestClass(int, int o = __builtin_COLUMN()) : x(o) {}
};
struct TestAggClass {
int x = __builtin_COLUMN();
};
constexpr bool test_class() {
auto check = [](int V, const char* S, int indent = 4) {
assert(V == (__builtin_strlen(S) + indent));
};
{
TestClass t{};
check(t.x, " T", 0); // Start of default constructor decl.
}
{
TestClass t1
{42};
check(t1.x, "TestClass t"); // Start of variable being constructed.
}
{
TestAggClass t { };
check(t.x, "TestAggClass t { }");
}
{
TestAggClass t = { };
check(t.x, "TestAggClass t = { }");
}
return true;
}
static_assert(test_class());
// clang-format on
} // namespace test_column
// Test [reflection.src_loc.creation]p2
// > The value should be affected by #line (C++14 16.4) in the same manner as
// > for __LINE__ and __FILE__.
namespace test_pragma_line {
constexpr int StartLine = 42;
#line 42
static_assert(__builtin_LINE() == StartLine);
static_assert(__builtin_LINE() == StartLine + 1);
static_assert(SL::current().line() == StartLine + 2);
#line 44 "test_file.c"
static_assert(is_equal("test_file.c", __FILE__));
static_assert(is_equal("test_file.c", __builtin_FILE()));
static_assert(is_equal("test_file.c", __builtin_FILE_NAME()));
static_assert(is_equal("test_file.c", SL::current().file()));
static_assert(is_equal("test_file.c", SLF::test_function().file()));
static_assert(is_equal(SLF::FILE, SLF::test_function_indirect().file()));
} // end namespace test_pragma_line
namespace test_out_of_line_init {
#line 4000 "test_out_of_line_init.cpp"
constexpr unsigned get_line(unsigned n = __builtin_LINE()) { return n; }
constexpr const char *get_file(const char *f = __builtin_FILE()) { return f; }
constexpr const char *get_func(const char *f = __builtin_FUNCTION()) { return f; }
#line 4100 "A.cpp"
struct A {
int n = __builtin_LINE();
int n2 = get_line();
const char *f = __builtin_FILE();
const char *f2 = get_file();
const char *func = __builtin_FUNCTION();
const char *func2 = get_func();
SL info = SL::current();
};
#line 4200 "B.cpp"
struct B {
A a = {};
};
#line 4300 "test_passed.cpp"
constexpr B b = {};
static_assert(b.a.n == 4300, "");
static_assert(b.a.n2 == 4300, "");
static_assert(b.a.info.line() == 4300, "");
static_assert(is_equal(b.a.f, "test_passed.cpp"));
static_assert(is_equal(b.a.f2, "test_passed.cpp"));
static_assert(is_equal(b.a.info.file(), "test_passed.cpp"));
static_assert(is_equal(b.a.func, ""));
static_assert(is_equal(b.a.func2, ""));
static_assert(is_equal(b.a.info.function(), ""));
constexpr bool test_in_func() {
#line 4400 "test_func_passed.cpp"
constexpr B b = {};
static_assert(b.a.n == 4400, "");
static_assert(b.a.n2 == 4400, "");
static_assert(b.a.info.line() == 4400, "");
static_assert(is_equal(b.a.f, "test_func_passed.cpp"));
static_assert(is_equal(b.a.f2, "test_func_passed.cpp"));
static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
static_assert(is_equal(b.a.func, "test_in_func"));
static_assert(is_equal(b.a.func2, "test_in_func"));
static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
return true;
}
static_assert(test_in_func());
} // end namespace test_out_of_line_init
namespace test_global_scope {
#line 5000 "test_global_scope.cpp"
constexpr unsigned get_line(unsigned n = __builtin_LINE()) { return n; }
constexpr const char *get_file(const char *f = __builtin_FILE()) { return f; }
constexpr const char *get_func(const char *f = __builtin_FUNCTION()) { return f; }
#line 5100
struct InInit {
unsigned l = get_line();
const char *f = get_file();
const char *func = get_func();
#line 5200 "in_init.cpp"
constexpr InInit() {}
};
#line 5300
constexpr InInit II;
static_assert(II.l == 5200, "");
static_assert(is_equal(II.f, "in_init.cpp"));
static_assert(is_equal(II.func, "InInit"));
#line 5400
struct AggInit {
unsigned l = get_line();
const char *f = get_file();
const char *func = get_func();
};
#line 5500 "brace_init.cpp"
constexpr AggInit AI = {};
static_assert(AI.l == 5500);
static_assert(is_equal(AI.f, "brace_init.cpp"));
static_assert(is_equal(AI.func, ""));
} // namespace test_global_scope
namespace TestFuncInInit {
#line 6000 "InitClass.cpp"
struct Init {
SL info;
#line 6100 "InitCtor.cpp"
constexpr Init(SL info = SL::current()) : info(info) {}
};
#line 6200 "InitGlobal.cpp"
constexpr Init I;
static_assert(I.info.line() == 6200);
static_assert(is_equal(I.info.file(), "InitGlobal.cpp"));
} // namespace TestFuncInInit
namespace TestConstexprContext {
#line 7000 "TestConstexprContext.cpp"
constexpr const char* foo() { return __builtin_FILE(); }
#line 7100 "Bar.cpp"
constexpr const char* bar(const char* x = foo()) { return x; }
constexpr bool test() {
static_assert(is_equal(bar(), "TestConstexprContext.cpp"));
return true;
}
static_assert(test());
}
namespace Lambda {
#line 8000 "TestLambda.cpp"
constexpr int nested_lambda(int l = []{
return SL::current().line();
}()) {
return l;
}
static_assert(nested_lambda() == __LINE__ - 4);
constexpr int lambda_param(int l = [](int l = SL::current().line()) {
return l;
}()) {
return l;
}
static_assert(lambda_param() == __LINE__);
}
constexpr int compound_literal_fun(int a =
(int){ SL::current().line() }
) { return a ;}
static_assert(compound_literal_fun() == __LINE__);
struct CompoundLiteral {
int a = (int){ SL::current().line() };
};
static_assert(CompoundLiteral{}.a == __LINE__);
// FIXME
// Init captures are subexpressions of the lambda expression
// so according to the standard immediate invocations in init captures
// should be evaluated at the call site.
// However Clang does not yet implement this as it would introduce
// a fair bit of complexity.
// We intend to implement that functionality once we find real world
// use cases that require it.
constexpr int test_init_capture(int a =
[b = SL::current().line()] { return b; }()) {
return a;
}
#if defined(USE_CONSTEVAL) && !defined(NEW_INTERP)
static_assert(test_init_capture() == __LINE__ - 4);
#else
static_assert(test_init_capture() == __LINE__ );
#endif
namespace check_immediate_invocations_in_templates {
template <typename T = int>
struct G {
T line = __builtin_LINE();
};
template <typename T>
struct S {
int i = G<T>{}.line;
};
static_assert(S<int>{}.i != // intentional new line
S<int>{}.i);
template <typename T>
constexpr int f(int i = G<T>{}.line) {
return i;
}
static_assert(f<int>() != // intentional new line
f<int>());
}
#ifdef PAREN_INIT
namespace GH63903 {
struct S {
int _;
int i = SL::current().line();
int j = __builtin_LINE();
};
// Ensure parent aggregate initialization is consistent with brace
// aggregate initialization.
// Note: consteval functions are evaluated where they are used.
static_assert(S(0).i == __builtin_LINE());
static_assert(S(0).i == S{0}.i);
static_assert(S(0).j == S{0}.j);
static_assert(S(0).j == S{0}.i);
}
#endif
namespace GH78128 {
template<int N>
constexpr int f() {
return N;
}
template<typename T>
void foo() {
constexpr auto* F1 = std::source_location::current().function();
static_assert(__builtin_strlen(F1) == f<__builtin_strlen(F1)>());
constexpr auto* F2 = __builtin_FUNCTION();
static_assert(__builtin_strlen(F2) == f<__builtin_strlen(F2)>());
#ifdef MS
constexpr auto* F3 = __builtin_FUNCSIG();
static_assert(__builtin_strlen(F3) == f<__builtin_strlen(F3)>());
#endif
}
void test() {
foo<int>();
}
}
namespace GH80630 {
#define GH80630_LAMBDA \
[]( char const* fn ) { \
static constexpr std::source_location loc = std::source_location::current(); \
return &loc; \
}( std::source_location::current().function() )
auto f( std::source_location const* loc = GH80630_LAMBDA ) {
return loc;
}
auto g() {
return f();
}
}
namespace GH92680 {
struct IntConstuctible {
IntConstuctible(std::source_location = std::source_location::current());
};
template <typename>
auto construct_at(IntConstuctible) -> decltype(IntConstuctible()) {
return {};
}
void test() {
construct_at<IntConstuctible>({});
}
}
namespace GH106428 {
struct add_fn {
template <typename T>
constexpr auto operator()(T lhs, T rhs,
const std::source_location loc = std::source_location::current())
const -> T
{
return lhs + rhs;
}
};
template <class _Fp, class... _Args>
decltype(_Fp{}(0, 0))
__invoke(_Fp&& __f);
template<typename T>
struct type_identity { using type = T; };
template<class Fn>
struct invoke_result : type_identity<decltype(__invoke(Fn{}))> {};
using i = invoke_result<add_fn>::type;
static_assert(__is_same(i, int));
}
#if __cplusplus >= 202002L
namespace GH81155 {
struct buff {
buff(buff &, const char * = __builtin_FUNCTION());
};
template <class Ty>
Ty declval();
template <class Fx>
auto Call(buff arg) -> decltype(Fx{}(arg));
template <typename>
struct F {};
template <class Fx>
struct InvocableR : F<decltype(Call<Fx>(declval<buff>()))> {
static constexpr bool value = false;
};
template <class Fx, bool = InvocableR<Fx>::value>
void Help(Fx) {}
void Test() {
Help([](buff) {});
}
}
#endif
namespace GH67134 {
template <int loc = std::source_location::current().line()>
constexpr auto f(std::source_location loc2 = std::source_location::current()) { return loc; }
int g = []() -> decltype(f()) { return 0; }();
int call() {
#if __cplusplus >= 202002L
return []<decltype(f()) = 0>() -> decltype(f()) { return 0; }();
#endif
return []() -> decltype(f()) { return 0; }();
}
#if __cplusplus >= 202002L
template<typename T>
int Var = requires { []() -> decltype(f()){}; };
int h = Var<int>;
#endif
}
namespace GH119129 {
struct X{
constexpr int foo(std::source_location loc = std::source_location::current()) {
return loc.line();
}
};
static_assert(X{}.foo() == __LINE__);
static_assert(X{}.
foo() == __LINE__);
static_assert(X{}.
foo() == __LINE__);
#line 10000
static_assert(X{}.
foo() == 10001);
}
#ifdef MS
namespace GH178324 {
struct a {
using e = int;
};
void current(const char * = __builtin_FUNCSIG());
template <class> void c() { decltype(a(current()))::e; }
} // namespace GH178324
#endif