Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][test] Avoid preprocessor directives in macro argument lists #73440

Merged
merged 1 commit into from
Nov 28, 2023

Conversation

StephanTLavavej
Copy link
Member

Found while running libc++'s test suite with MSVC's STL.

MSVC has a level 1 "warning C5101: use of preprocessor directive in function-like macro argument list is undefined behavior". I don't know why Clang doesn't complain about this.

There are some formatting tests which densely interleave preprocessor directives within function-like macros, and they would need invasive changes. For now, I'm just skipping those tests.

However, a few tests were only slightly affected, and I was able to add a new test macro TEST_IF_AIX to make them portable.

…n function-like macro argument list is undefined behavior
@StephanTLavavej StephanTLavavej requested a review from a team as a code owner November 26, 2023 11:06
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 26, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 26, 2023

@llvm/pr-subscribers-libcxx

Author: Stephan T. Lavavej (StephanTLavavej)

Changes

Found while running libc++'s test suite with MSVC's STL.

MSVC has a level 1 "warning C5101: use of preprocessor directive in function-like macro argument list is undefined behavior". I don't know why Clang doesn't complain about this.

There are some formatting tests which densely interleave preprocessor directives within function-like macros, and they would need invasive changes. For now, I'm just skipping those tests.

However, a few tests were only slightly affected, and I was able to add a new test macro TEST_IF_AIX to make them portable.


Full diff: https://github.com/llvm/llvm-project/pull/73440.diff

5 Files Affected:

  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/print.file.pass.cpp (+2-5)
  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp (+2-5)
  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.file.pass.cpp (+2-5)
  • (modified) libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.file.pass.cpp (+2-5)
  • (modified) libcxx/test/support/test_macros.h (+6)
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/print.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/print.file.pass.cpp
index 4a397d3e3d6328f..3edc0e2245d649e 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/print.file.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/print.file.pass.cpp
@@ -94,11 +94,8 @@ static void test_read_only() {
   TEST_VALIDATE_EXCEPTION(
       std::system_error,
       [&]([[maybe_unused]] const std::system_error& e) {
-#ifdef _AIX
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Broken pipe"};
-#else
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Operation not permitted"};
-#endif
+        [[maybe_unused]] std::string_view what{
+            "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")};
         TEST_LIBCPP_REQUIRE(
             e.what() == what,
             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp
index ebdddd074faf51c..07272ebb57e5fc1 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/println.file.pass.cpp
@@ -97,11 +97,8 @@ static void test_read_only() {
   TEST_VALIDATE_EXCEPTION(
       std::system_error,
       [&]([[maybe_unused]] const std::system_error& e) {
-#ifdef _AIX
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Broken pipe"};
-#else
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Operation not permitted"};
-#endif
+        [[maybe_unused]] std::string_view what{
+            "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")};
         TEST_LIBCPP_REQUIRE(
             e.what() == what,
             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.file.pass.cpp
index 9eb85f3b7b2d874..edc8bb3f543c466 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.file.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.file.pass.cpp
@@ -103,11 +103,8 @@ static void test_read_only() {
   TEST_VALIDATE_EXCEPTION(
       std::system_error,
       [&]([[maybe_unused]] const std::system_error& e) {
-#ifdef _AIX
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Broken pipe"};
-#else
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Operation not permitted"};
-#endif
+        [[maybe_unused]] std::string_view what{
+            "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")};
         TEST_LIBCPP_REQUIRE(
             e.what() == what,
             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.file.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.file.pass.cpp
index 28379b9db50ed58..bd9b99166922ff0 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.file.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.file.pass.cpp
@@ -110,11 +110,8 @@ static void test_read_only() {
   TEST_VALIDATE_EXCEPTION(
       std::system_error,
       [&]([[maybe_unused]] const std::system_error& e) {
-#ifdef _AIX
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Broken pipe"};
-#else
-        [[maybe_unused]] std::string_view what{"failed to write formatted output: Operation not permitted"};
-#endif
+        [[maybe_unused]] std::string_view what{
+            "failed to write formatted output: " TEST_IF_AIX("Broken pipe", "Operation not permitted")};
         TEST_LIBCPP_REQUIRE(
             e.what() == what,
             TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index e549ec2ca7a1a71..f3c6d8080ff6d83 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -443,4 +443,10 @@ inline void DoNotOptimize(Tp const& value) {
 #  define TEST_WORKAROUND_BUG_109234844_WEAK /* nothing */
 #endif
 
+#ifdef _AIX
+#  define TEST_IF_AIX(arg_true, arg_false) arg_true
+#else
+#  define TEST_IF_AIX(arg_true, arg_false) arg_false
+#endif
+
 #endif // SUPPORT_TEST_MACROS_HPP

Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed odd that Clang does no complain about this,
Would it be possible to file a bug report with the MSVC error messages?

LGTM!

@StephanTLavavej
Copy link
Member Author

Thanks! I filed a Clang bug report, after looking up the relevant Standardese saying it's UB. The CI failures here are spurious, so I'll go ahead and merge.

BTW, the remaining affected tests (that had way more occurrences that I couldn't easily fix) are:

std/time/time.syn/formatter.duration.pass.cpp
std/time/time.syn/formatter.file_time.pass.cpp
std/time/time.syn/formatter.hh_mm_ss.pass.cpp
std/time/time.syn/formatter.local_time.pass.cpp
std/time/time.syn/formatter.sys_time.pass.cpp
std/time/time.syn/formatter.year.pass.cpp
std/time/time.syn/formatter.year_month.pass.cpp
std/time/time.syn/formatter.year_month_day_last.pass.cpp
std/time/time.syn/formatter.year_month_weekday.pass.cpp

@StephanTLavavej StephanTLavavej merged commit a3529aa into llvm:main Nov 28, 2023
37 of 39 checks passed
@StephanTLavavej StephanTLavavej deleted the stl-5-preprocessor branch November 28, 2023 01:38
@mordante
Copy link
Member

Thanks for filing a Clang bug, I files a libc++ bug for myself to track the libc++ issues.

ldionne pushed a commit that referenced this pull request May 28, 2024
Found while running libc++'s tests with MSVC's STL.

* Avoid MSVC warning C5101: use of preprocessor directive in
function-like macro argument list is undefined behavior.
+ We can easily make this portable by extracting `const bool is_newlib`.
  + Followup to #73440.
  + See #73598.
  + See #73836.
* Avoid MSVC warning C4267: 'return': conversion from 'size_t' to 'int',
possible loss of data.
+ This warning is valid, but harmless for the test, so
`static_cast<int>` will avoid it.
* Avoid MSVC warning C4146: unary minus operator applied to unsigned
type, result still unsigned.
+ This warning is also valid (the scenario is sometimes intentional, but
surprising enough that it's worth warning about). This is a C++17 test,
so we can easily avoid it by testing `is_signed_v` at compile-time
before testing `m < 0` and `n < 0` at run-time.
* Silence MSVC warning C4310: cast truncates constant value.
+ These warnings are being emitted by `T(255)`. Disabling the warning is
simpler than attempting to restructure the code.
  + Followup to #79791.
* MSVC no longer emits warning C4521: multiple copy constructors
specified.
+ This warning was removed from the compiler, since at least 2021-12-09.
vg0204 pushed a commit to vg0204/llvm-project that referenced this pull request May 29, 2024
Found while running libc++'s tests with MSVC's STL.

* Avoid MSVC warning C5101: use of preprocessor directive in
function-like macro argument list is undefined behavior.
+ We can easily make this portable by extracting `const bool is_newlib`.
  + Followup to llvm#73440.
  + See llvm#73598.
  + See llvm#73836.
* Avoid MSVC warning C4267: 'return': conversion from 'size_t' to 'int',
possible loss of data.
+ This warning is valid, but harmless for the test, so
`static_cast<int>` will avoid it.
* Avoid MSVC warning C4146: unary minus operator applied to unsigned
type, result still unsigned.
+ This warning is also valid (the scenario is sometimes intentional, but
surprising enough that it's worth warning about). This is a C++17 test,
so we can easily avoid it by testing `is_signed_v` at compile-time
before testing `m < 0` and `n < 0` at run-time.
* Silence MSVC warning C4310: cast truncates constant value.
+ These warnings are being emitted by `T(255)`. Disabling the warning is
simpler than attempting to restructure the code.
  + Followup to llvm#79791.
* MSVC no longer emits warning C4521: multiple copy constructors
specified.
+ This warning was removed from the compiler, since at least 2021-12-09.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants