Skip to content

Commit 8504e86

Browse files
committed
Auto-enable file/line/function info on contracts violations + usability improvements
Thanks @MikeShah for your YouTube video here: https://youtu.be/ZslemeHsOjk?si=qPoNdJLxBoSgFh6b . I'm treating the video as a "looking over your shoulder using Cpp2" mini-UX study to make a better experience for folks coming to the syntax the first time... Diagnose attempt to declare two things at once, e.g., `x,y : int = 5;` Diagnose attempt to for-loop over two ranges, e.g., `for x,y do ..` Automatically use <source_location>, including for file/line/function information on contracts checks so when using a capable compiler you get nice bounds/other violation messages out of the box that point directly to the offending source line Remove the -add-source-info flag as no longer needed, now <source_location> is now reliable and automated (modulo a workaround in cpp2util.h for an MSVC bug where importing source_location via a module doesn't work correctly)
1 parent a252d50 commit 8504e86

26 files changed

+92
-59
lines changed

include/cpp2util.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@
4343

4444
// If this implementation doesn't support source_location yet, disable it
4545
#include <version>
46-
#if !defined(_MSC_VER) && !defined(__cpp_lib_source_location)
47-
#undef CPP2_USE_SOURCE_LOCATION
46+
47+
#undef CPP2_USE_SOURCE_LOCATION
48+
#if defined(__cpp_lib_source_location)
49+
#define CPP2_USE_SOURCE_LOCATION Yes
4850
#endif
4951

5052
// If the user requested making the entire C++ standard library available
@@ -553,15 +555,17 @@ auto pointer_eq(T const* a, T const* b) {
553555
//
554556

555557
#ifdef CPP2_USE_SOURCE_LOCATION
556-
#define CPP2_SOURCE_LOCATION_PARAM , std::source_location where
557-
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , std::source_location where = std::source_location::current()
558-
#define CPP2_SOURCE_LOCATION_PARAM_SOLO std::source_location where
558+
#define CPP2_SOURCE_LOCATION_PARAM , [[maybe_unused]] std::source_location where
559+
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , [[maybe_unused]] std::source_location where = std::source_location::current()
560+
#define CPP2_SOURCE_LOCATION_PARAM_SOLO [[maybe_unused]] std::source_location where
559561
#define CPP2_SOURCE_LOCATION_ARG , where
562+
#define CPP2_SOURCE_LOCATION_VALUE (cpp2::to_string(where.file_name()) + "(" + cpp2::to_string(where.line()) + ") " + where.function_name())
560563
#else
561564
#define CPP2_SOURCE_LOCATION_PARAM
562565
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
563566
#define CPP2_SOURCE_LOCATION_PARAM_SOLO
564567
#define CPP2_SOURCE_LOCATION_ARG
568+
#define CPP2_SOURCE_LOCATION_VALUE std::string("")
565569
#endif
566570

567571
// For C++23: make this std::string_view and drop the macro
@@ -1520,8 +1524,16 @@ inline constexpr auto as() -> auto
15201524
return cpp2::to_string(CPP2_FORWARD(x));
15211525
}
15221526

1527+
// Work around MSVC modules bugs: source_location doesn't work correctly if imported via a module
1528+
#if defined(_MSC_VER) && defined(CPP2_IMPORT_STD)
1529+
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS
1530+
#define CPP2_SOURCE_LOCATION_ARG_AS
1531+
#else
1532+
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
1533+
#define CPP2_SOURCE_LOCATION_ARG_AS CPP2_SOURCE_LOCATION_ARG
1534+
#endif
15231535
template< typename C >
1524-
auto as(auto&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> decltype(auto)
1536+
auto as(auto&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT_AS) -> decltype(auto)
15251537
// This "requires" list may need to be tweaked further. The idea is to have
15261538
// this function used for all the cases it's supposed to cover, but not
15271539
// hide user-supplied extensions (such as the ones later in this file for
@@ -1555,7 +1567,7 @@ auto as(auto&& x CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> decltype(auto)
15551567
const C c = static_cast<C>(CPP2_FORWARD(x));
15561568
type_safety.enforce( // precondition check: must be round-trippable => not lossy
15571569
static_cast<CPP2_TYPEOF(x)>(c) == x && (c < C{}) == (x < CPP2_TYPEOF(x){}),
1558-
"dynamic lossy narrowing conversion attempt detected" CPP2_SOURCE_LOCATION_ARG
1570+
"dynamic lossy narrowing conversion attempt detected" CPP2_SOURCE_LOCATION_ARG_AS
15591571
);
15601572
return CPP2_COPY(c);
15611573
}

regression-tests/mixed-lifetime-safety-and-null-contracts.cpp2

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@ try_pointer_stuff: () = {
1818
// to show -n
1919
}
2020

21-
call_my_framework: (msg: * const char) = {
21+
auto call_my_framework(const char* msg CPP2_SOURCE_LOCATION_PARAM) {
2222
std::cout
2323
<< "sending error to my framework... ["
24-
<< msg << "]\n";
24+
<< msg
25+
<< "]\n";
26+
auto loc = CPP2_SOURCE_LOCATION_VALUE;
27+
if (!loc.empty()) {
28+
std::cout
29+
<< "from source location: "
30+
<< loc
31+
<< "]\n";
32+
}
2533
exit(0);
2634
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Bounds safety violation: out of bounds access attempt detected - attempted access at index 5, [min,max] range is [0,4]
1+
mixed-bounds-check.cpp2(9) int main(): Bounds safety violation: out of bounds access attempt detected - attempted access at index 5, [min,max] range is [0,4]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Bounds safety violation
1+
mixed-bounds-safety-with-assert.cpp2(11) void print_subrange(const auto:89&, cpp2::impl::in<int>, cpp2::impl::in<int>) [with auto:89 = std::vector<int>; cpp2::impl::in<int> = const int]: Bounds safety violation
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
11
In file included from mixed-bugfix-for-ufcs-non-local.cpp:6:
22
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
3-
2100 | template<typename T>
3+
2100 | {
44
| ^
55
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
6-
2137 | class c_raii {
6+
2137 | // Speculative: RAII wrapping for the C standard library
77
| ^
88
mixed-bugfix-for-ufcs-non-local.cpp2:13:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
99
mixed-bugfix-for-ufcs-non-local.cpp2:13:36: error: template argument 1 is invalid
1010
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
11-
2100 | template<typename T>
11+
2100 | {
1212
| ^
1313
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
14-
2137 | class c_raii {
14+
2137 | // Speculative: RAII wrapping for the C standard library
1515
| ^
1616
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
1717
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
1818
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
19-
2100 | template<typename T>
19+
2100 | {
2020
| ^
2121
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
22-
2137 | class c_raii {
22+
2137 | // Speculative: RAII wrapping for the C standard library
2323
| ^
2424
mixed-bugfix-for-ufcs-non-local.cpp2:31:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
2525
mixed-bugfix-for-ufcs-non-local.cpp2:31:36: error: template argument 1 is invalid
2626
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
27-
2100 | template<typename T>
27+
2100 | {
2828
| ^
2929
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
30-
2137 | class c_raii {
30+
2137 | // Speculative: RAII wrapping for the C standard library
3131
| ^
3232
mixed-bugfix-for-ufcs-non-local.cpp2:33:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
3333
mixed-bugfix-for-ufcs-non-local.cpp2:33:36: error: template argument 1 is invalid
3434
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
35-
2100 | template<typename T>
35+
2100 | {
3636
| ^
3737
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
38-
2137 | class c_raii {
38+
2137 | // Speculative: RAII wrapping for the C standard library
3939
| ^
4040
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
4141
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Contract violation: fill: value must contain at least count elements
1+
mixed-initialization-safety-3-contract-violation.cpp2(25) void fill(cpp2::impl::out<std::__cxx11::basic_string<char> >, cpp2::impl::in<std::__cxx11::basic_string<char> >, cpp2::impl::in<int>): Contract violation: fill: value must contain at least count elements
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
sending error to my framework... [dynamic null dereference attempt detected]
2+
from source location: mixed-lifetime-safety-and-null-contracts.cpp2(17) void try_pointer_stuff()]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Null safety violation: std::expected has an unexpected value
1+
pure2-assert-expected-not-null.cpp2(15) int bad_expected_access(): Null safety violation: std::expected has an unexpected value
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Null safety violation: std::optional does not contain a value
1+
pure2-assert-optional-not-null.cpp2(14) int bad_optional_access(): Null safety violation: std::optional does not contain a value
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Null safety violation: std::shared_ptr is empty
1+
pure2-assert-shared-ptr-not-null.cpp2(15) int bad_shared_ptr_access(): Null safety violation: std::shared_ptr is empty

0 commit comments

Comments
 (0)