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] force GCC limits.h to not include_next limits.h #79211

Closed
wants to merge 3 commits into from

Conversation

nickdesaulniers
Copy link
Member

Who defines what the width and thus the min/max values for a given integer
type? We'd like to rely on the compiler's resource dir's definitions, but GCC's
limits.h can end up using include_next to include limits.h from GLIBC.

This results in build failures with GCC due to __GLIBC_USE being undefined (a
feature detection macro defined only relevant to glibc). We'd like to avoid
the compiler pulling in the libc's headers (unless there's some critical reason
why, which we don't have today AFAIK). GCC's limits.h will avoid this circular
includes if LIBC_LIMITS_H is defined.

GCC's limits.h only defines LLONG_MAX, LLONG_MIN, and ULLONG_MAX if
STDC_VERSION is defined and >= 199901L, i.e. not for C++, so provide those
definitions ourselves.

Due to this, we should never be including <limits.h> in libc/ (other than in
CPP/limits.h). Sources and tests should be including
"libc/src/__support/CPP/limits.h" in place of <limits.h>.

Who defines what the width and thus the min/max values for a given integer
type? We'd like to rely on the compiler's resource dir's definitions, but GCC's
limits.h can end up using include_next to include limits.h from GLIBC.

This results in build failures with GCC due to __GLIBC_USE being undefined (a
feature detection macro defined only relevant to glibc). We'd like to avoid
the compiler pulling in the libc's headers (unless there's some critical reason
why, which we don't have today AFAIK). GCC's limits.h will avoid this circular
includes if _LIBC_LIMITS_H_ is defined.

GCC's limits.h only defines LLONG_MAX, LLONG_MIN, and ULLONG_MAX if
__STDC_VERSION__ is defined and >= 199901L, i.e. not for C++, so provide those
definitions ourselves.

Due to this, we should never be including <limits.h> in libc/ (other than in
CPP/limits.h). Sources and tests should be including
"libc/src/__support/CPP/limits.h" in place of <limits.h>.
@llvmbot llvmbot added the libc label Jan 23, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 23, 2024

@llvm/pr-subscribers-libc

Author: Nick Desaulniers (nickdesaulniers)

Changes

Who defines what the width and thus the min/max values for a given integer
type? We'd like to rely on the compiler's resource dir's definitions, but GCC's
limits.h can end up using include_next to include limits.h from GLIBC.

This results in build failures with GCC due to __GLIBC_USE being undefined (a
feature detection macro defined only relevant to glibc). We'd like to avoid
the compiler pulling in the libc's headers (unless there's some critical reason
why, which we don't have today AFAIK). GCC's limits.h will avoid this circular
includes if LIBC_LIMITS_H is defined.

GCC's limits.h only defines LLONG_MAX, LLONG_MIN, and ULLONG_MAX if
STDC_VERSION is defined and >= 199901L, i.e. not for C++, so provide those
definitions ourselves.

Due to this, we should never be including <limits.h> in libc/ (other than in
CPP/limits.h). Sources and tests should be including
"libc/src/__support/CPP/limits.h" in place of <limits.h>.


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

23 Files Affected:

  • (modified) libc/src/__support/CPP/limits.h (+17)
  • (modified) libc/src/__support/FPUtil/ManipulationFunctions.h (+1-1)
  • (modified) libc/src/__support/math_extras.h (+1-2)
  • (modified) libc/src/__support/str_to_integer.h (-1)
  • (modified) libc/src/__support/threads/linux/callonce.cpp (+1-1)
  • (modified) libc/src/threads/linux/call_once.cpp (+1-1)
  • (modified) libc/src/time/mktime.cpp (+1-2)
  • (modified) libc/src/time/time_utils.cpp (+1-2)
  • (modified) libc/test/src/math/ILogbTest.h (+1-2)
  • (modified) libc/test/src/math/LdExpTest.h (+1-1)
  • (modified) libc/test/src/math/smoke/ILogbTest.h (+1-2)
  • (modified) libc/test/src/math/smoke/LdExpTest.h (+1-1)
  • (modified) libc/test/src/stdlib/AtoiTest.h (+1-2)
  • (modified) libc/test/src/stdlib/StrtolTest.h (-1)
  • (modified) libc/test/src/stdlib/atof_test.cpp (+1-1)
  • (modified) libc/test/src/stdlib/strtod_test.cpp (+1-1)
  • (modified) libc/test/src/stdlib/strtof_test.cpp (+1-1)
  • (modified) libc/test/src/stdlib/strtold_test.cpp (+1-1)
  • (modified) libc/test/src/time/CMakeLists.txt (+4-1)
  • (modified) libc/test/src/time/clock_test.cpp (+1-1)
  • (modified) libc/test/src/time/gmtime_test.cpp (+1-2)
  • (modified) libc/test/src/time/mktime_test.cpp (+1-2)
  • (modified) libc/test/src/time/time_test.cpp (-1)
diff --git a/libc/src/__support/CPP/limits.h b/libc/src/__support/CPP/limits.h
index d9e7090a0b7b190..11af4b30eaf745e 100644
--- a/libc/src/__support/CPP/limits.h
+++ b/libc/src/__support/CPP/limits.h
@@ -13,8 +13,25 @@
 #include "src/__support/CPP/type_traits/is_signed.h"
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 
+// Coax GCC to NOT attempt to include_next limits.h from glibc. llvmlibc should
+// include this file rather than <limits.h> directy for this reason.
+#ifndef __clang__
+#define _LIBC_LIMITS_H_
+#endif
 #include <limits.h> // CHAR_BIT
 
+// GCC's limits.h only defines these for __STDC_VERSION__ >= 199901L, i.e. not
+// C++.
+#ifndef LLONG_MAX
+#define LLONG_MAX __LONG_LONG_MAX__
+#endif
+#ifndef LLONG_MIN
+#define LLONG_MIN (-LONG_MAX - 1LL)
+#endif
+#ifndef ULLONG_MAX
+#define ULLONG_MAX (~0ULL)
+#endif
+
 namespace LIBC_NAMESPACE {
 namespace cpp {
 
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index 81c8281f3c7bbee..589cd9c4cfb7af7 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -14,12 +14,12 @@
 #include "NormalFloat.h"
 
 #include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/limits.h" // INT_MAX, INT_MIN
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/macros/attributes.h"
 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
 
-#include <limits.h>
 #include <math.h>
 
 namespace LIBC_NAMESPACE {
diff --git a/libc/src/__support/math_extras.h b/libc/src/__support/math_extras.h
index 89bd0b72669ea22..8ec30396ffdb460 100644
--- a/libc/src/__support/math_extras.h
+++ b/libc/src/__support/math_extras.h
@@ -10,12 +10,11 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H
 
+#include "src/__support/CPP/limits.h"        // CHAR_BIT
 #include "src/__support/CPP/type_traits.h"   // is_unsigned_v
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/config.h"     // LIBC_HAS_BUILTIN
 
-#include <limits.h> // CHAR_BIT
-
 namespace LIBC_NAMESPACE {
 
 // Create a bitmask with the count right-most bits set to 1, and all other bits
diff --git a/libc/src/__support/str_to_integer.h b/libc/src/__support/str_to_integer.h
index 4ee336ec9e2bbd8..e83a508e086b18a 100644
--- a/libc/src/__support/str_to_integer.h
+++ b/libc/src/__support/str_to_integer.h
@@ -15,7 +15,6 @@
 #include "src/__support/ctype_utils.h"
 #include "src/__support/str_to_num_result.h"
 #include "src/errno/libc_errno.h" // For ERANGE
-#include <limits.h>
 
 namespace LIBC_NAMESPACE {
 namespace internal {
diff --git a/libc/src/__support/threads/linux/callonce.cpp b/libc/src/__support/threads/linux/callonce.cpp
index de1e1008784f604..ec66d41c559a0be 100644
--- a/libc/src/__support/threads/linux/callonce.cpp
+++ b/libc/src/__support/threads/linux/callonce.cpp
@@ -9,10 +9,10 @@
 #include "futex_word.h"
 
 #include "src/__support/CPP/atomic.h"
+#include "src/__support/CPP/limits.h"
 #include "src/__support/OSUtil/syscall.h" // For syscall functions.
 #include "src/__support/threads/callonce.h"
 
-#include <limits.h>
 #include <linux/futex.h>
 #include <sys/syscall.h> // For syscall numbers.
 
diff --git a/libc/src/threads/linux/call_once.cpp b/libc/src/threads/linux/call_once.cpp
index 5cdd8ebfd190ea1..dc36304282355ae 100644
--- a/libc/src/threads/linux/call_once.cpp
+++ b/libc/src/threads/linux/call_once.cpp
@@ -9,12 +9,12 @@
 #include "Futex.h"
 
 #include "src/__support/CPP/atomic.h"
+#include "src/__support/CPP/limits.h"
 #include "src/__support/OSUtil/syscall.h" // For syscall functions.
 #include "src/__support/common.h"
 #include "src/threads/call_once.h"
 #include "src/threads/linux/Futex.h"
 
-#include <limits.h>
 #include <linux/futex.h>
 #include <sys/syscall.h> // For syscall numbers.
 #include <threads.h>     // For call_once related type definition.
diff --git a/libc/src/time/mktime.cpp b/libc/src/time/mktime.cpp
index e57565f0d1fe016..12a1e690b0f23cc 100644
--- a/libc/src/time/mktime.cpp
+++ b/libc/src/time/mktime.cpp
@@ -7,11 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/time/mktime.h"
+#include "src/__support/CPP/limits.h"
 #include "src/__support/common.h"
 #include "src/time/time_utils.h"
 
-#include <limits.h>
-
 namespace LIBC_NAMESPACE {
 
 using LIBC_NAMESPACE::time_utils::TimeConstants;
diff --git a/libc/src/time/time_utils.cpp b/libc/src/time/time_utils.cpp
index 199a74cb168a2c3..5fd988661383e2a 100644
--- a/libc/src/time/time_utils.cpp
+++ b/libc/src/time/time_utils.cpp
@@ -7,10 +7,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/time/time_utils.h"
+#include "src/__support/CPP/limits.h"
 #include "src/__support/common.h"
 
-#include <limits.h>
-
 namespace LIBC_NAMESPACE {
 namespace time_utils {
 
diff --git a/libc/test/src/math/ILogbTest.h b/libc/test/src/math/ILogbTest.h
index 9fa25c9ff986148..d2e8e40a3add283 100644
--- a/libc/test/src/math/ILogbTest.h
+++ b/libc/test/src/math/ILogbTest.h
@@ -9,13 +9,12 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_ILOGBTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_ILOGBTEST_H
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/ManipulationFunctions.h"
 #include "test/UnitTest/Test.h"
 #include <math.h>
 
-#include <limits.h>
-
 class LlvmLibcILogbTest : public LIBC_NAMESPACE::testing::Test {
 public:
   template <typename T> struct ILogbFunc {
diff --git a/libc/test/src/math/LdExpTest.h b/libc/test/src/math/LdExpTest.h
index 25120ba3646fda0..0b9ddf13a2a8af8 100644
--- a/libc/test/src/math/LdExpTest.h
+++ b/libc/test/src/math/LdExpTest.h
@@ -9,12 +9,12 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_LDEXPTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_LDEXPTEST_H
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/NormalFloat.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <math.h>
 #include <stdint.h>
 
diff --git a/libc/test/src/math/smoke/ILogbTest.h b/libc/test/src/math/smoke/ILogbTest.h
index 0a50abc04f727f1..9f415f1c664fada 100644
--- a/libc/test/src/math/smoke/ILogbTest.h
+++ b/libc/test/src/math/smoke/ILogbTest.h
@@ -9,13 +9,12 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_ILOGBTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_ILOGBTEST_H
 
+#include "src/__support/CPP/limits.h" // INT_MAX
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/ManipulationFunctions.h"
 #include "test/UnitTest/Test.h"
 #include <math.h>
 
-#include <limits.h>
-
 class LlvmLibcILogbTest : public LIBC_NAMESPACE::testing::Test {
 public:
   template <typename T> struct ILogbFunc {
diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h
index 25120ba3646fda0..da69b85dced163c 100644
--- a/libc/test/src/math/smoke/LdExpTest.h
+++ b/libc/test/src/math/smoke/LdExpTest.h
@@ -9,12 +9,12 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_LDEXPTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_LDEXPTEST_H
 
+#include "src/__support/CPP/limits.h" // INT_MAX
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/NormalFloat.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <math.h>
 #include <stdint.h>
 
diff --git a/libc/test/src/stdlib/AtoiTest.h b/libc/test/src/stdlib/AtoiTest.h
index 85701828c0f6b7c..add510f468f55a1 100644
--- a/libc/test/src/stdlib/AtoiTest.h
+++ b/libc/test/src/stdlib/AtoiTest.h
@@ -6,11 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/CPP/type_traits.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
-
 using LIBC_NAMESPACE::cpp::is_same_v;
 
 template <typename ReturnT>
diff --git a/libc/test/src/stdlib/StrtolTest.h b/libc/test/src/stdlib/StrtolTest.h
index 11794c4bfe05f8a..6aee049aa066a04 100644
--- a/libc/test/src/stdlib/StrtolTest.h
+++ b/libc/test/src/stdlib/StrtolTest.h
@@ -12,7 +12,6 @@
 #include "src/errno/libc_errno.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <stddef.h>
 
 using LIBC_NAMESPACE::cpp::is_signed_v;
diff --git a/libc/test/src/stdlib/atof_test.cpp b/libc/test/src/stdlib/atof_test.cpp
index ed3d4c26308cb23..65172b90072bdad 100644
--- a/libc/test/src/stdlib/atof_test.cpp
+++ b/libc/test/src/stdlib/atof_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/errno/libc_errno.h"
 #include "src/stdlib/atof.h"
@@ -13,7 +14,6 @@
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <stddef.h>
 
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
diff --git a/libc/test/src/stdlib/strtod_test.cpp b/libc/test/src/stdlib/strtod_test.cpp
index b1bdd89e41fd151..70ab65df61899e2 100644
--- a/libc/test/src/stdlib/strtod_test.cpp
+++ b/libc/test/src/stdlib/strtod_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/errno/libc_errno.h"
 #include "src/stdlib/strtod.h"
@@ -14,7 +15,6 @@
 #include "test/UnitTest/RoundingModeUtils.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <stddef.h>
 
 using LIBC_NAMESPACE::fputil::testing::ForceRoundingModeTest;
diff --git a/libc/test/src/stdlib/strtof_test.cpp b/libc/test/src/stdlib/strtof_test.cpp
index 15a8a34ef4fb171..b25a9068bbfe52e 100644
--- a/libc/test/src/stdlib/strtof_test.cpp
+++ b/libc/test/src/stdlib/strtof_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/errno/libc_errno.h"
 #include "src/stdlib/strtof.h"
@@ -14,7 +15,6 @@
 #include "test/UnitTest/RoundingModeUtils.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <stddef.h>
 
 using LIBC_NAMESPACE::fputil::testing::ForceRoundingModeTest;
diff --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp
index 51f9975772aa5e9..832d11ea1f3daf1 100644
--- a/libc/test/src/stdlib/strtold_test.cpp
+++ b/libc/test/src/stdlib/strtold_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/UInt128.h"
 #include "src/errno/libc_errno.h"
@@ -13,7 +14,6 @@
 
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <stddef.h>
 
 #if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 10b63ce6f39d295..ec274863f2feca9 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -71,6 +71,7 @@ add_libc_unittest(
     TmMatcher.h
   DEPENDS
     libc.src.time.gmtime
+    libc.src.__support.CPP.limits
 )
 
 add_libc_unittest(
@@ -98,6 +99,7 @@ add_libc_unittest(
     20
   DEPENDS
     libc.src.time.mktime
+    libc.src.__support.CPP.limits
 )
 
 # Sleeping is not supported on older NVPTX architectures.
@@ -136,6 +138,7 @@ add_libc_test(
     clock_test.cpp
   DEPENDS
     libc.include.time
-    libc.src.time.clock
+    libc.src.__support.CPP.limits
     libc.src.errno.errno
+    libc.src.time.clock
 )
diff --git a/libc/test/src/time/clock_test.cpp b/libc/test/src/time/clock_test.cpp
index a3dffc6bae3913d..99a2233da13803a 100644
--- a/libc/test/src/time/clock_test.cpp
+++ b/libc/test/src/time/clock_test.cpp
@@ -6,10 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/time/clock.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <time.h>
 
 TEST(LlvmLibcClockTest, SmokeTest) {
diff --git a/libc/test/src/time/gmtime_test.cpp b/libc/test/src/time/gmtime_test.cpp
index 6b1d029a693c383..c42588947710f89 100644
--- a/libc/test/src/time/gmtime_test.cpp
+++ b/libc/test/src/time/gmtime_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/errno/libc_errno.h"
 #include "src/time/gmtime.h"
 #include "src/time/time_utils.h"
@@ -13,8 +14,6 @@
 #include "test/UnitTest/Test.h"
 #include "test/src/time/TmMatcher.h"
 
-#include <limits.h>
-
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LIBC_NAMESPACE::time_utils::TimeConstants;
diff --git a/libc/test/src/time/mktime_test.cpp b/libc/test/src/time/mktime_test.cpp
index 6f179150953b7f1..8dc65e2406f6347 100644
--- a/libc/test/src/time/mktime_test.cpp
+++ b/libc/test/src/time/mktime_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/limits.h"
 #include "src/time/mktime.h"
 #include "src/time/time_utils.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
@@ -13,8 +14,6 @@
 #include "test/src/time/TmHelper.h"
 #include "test/src/time/TmMatcher.h"
 
-#include <limits.h>
-
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LIBC_NAMESPACE::time_utils::Month;
diff --git a/libc/test/src/time/time_test.cpp b/libc/test/src/time/time_test.cpp
index 1d938e8dae7adb2..d3d4dc9a285158e 100644
--- a/libc/test/src/time/time_test.cpp
+++ b/libc/test/src/time/time_test.cpp
@@ -9,7 +9,6 @@
 #include "src/time/time_func.h"
 #include "test/UnitTest/Test.h"
 
-#include <limits.h>
 #include <time.h>
 
 TEST(LlvmLibcTimeTest, SmokeTest) {

@@ -136,6 +138,7 @@ add_libc_test(
clock_test.cpp
DEPENDS
libc.include.time
libc.src.time.clock
libc.src.__support.CPP.limits
Copy link
Member Author

Choose a reason for hiding this comment

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

it's unclear to me when we need to add these DEPENDS vs not. I didn't for many changes, and the build succeeds. Is that expected? Do we have some convention here that perhaps I'm unaware of?

Copy link
Contributor

Choose a reason for hiding this comment

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

DEPENDS primarily tells cmake which object files need to be linked. For header files it's technically unnecessary, though we should still do it to make sure that cmake properly rebuilds targets that depend on those header files.

Copy link
Member Author

Choose a reason for hiding this comment

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

If I change this line in particular s/limits/asdfasdfasdf/ literally nothing happens to the build...that doesn't instill confidence that this change is even doing anything...

Copy link
Contributor

@SchrodingerZhu SchrodingerZhu Jan 23, 2024

Choose a reason for hiding this comment

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

After an "unknown" change sometime ago, if you miss the generated header dependency in full build, the header may not be generated in time. This results in most of the full build failures that we have been fixing.

Copy link
Contributor

Choose a reason for hiding this comment

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

The reason the build doesn't fail when you add an invalid dependency is because the cmake checks the dependencies when it's generating the targets. If you turn on verbose logging you should see something like -- Skipping unittest libc.test.src.time.clock_test.__unit__ as it has missing deps: libc.src.asdfasdfasdf. when you rerun the cmake, and also if you specifically run that test with ninja libc.test.src.time.clock_test.__unit__ it will say it can't find the target.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is that a feature or a bug?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's a feature, so that we skip the tests if its entrypoints are not enabled instead of erroring out, or something like that.

@jhuber6
Copy link
Contributor

jhuber6 commented Jan 23, 2024

Seems weird to make clang the one that we can include_next considering the whole point of this was to work around the compiler's lack of support. If it's just a clang thing then we just add it to clang/lib/Headers/ and be done with it.

@nickdesaulniers
Copy link
Member Author

Seems weird to make clang the one that we can include_next

Where is include_next that you're referring to?

@jhuber6
Copy link
Contributor

jhuber6 commented Jan 23, 2024

Seems weird to make clang the one that we can include_next

Where is include_next that you're referring to?

I'm unsure how we expect all of these to work. The compiler provides resource directories, which then include the system's versions unless STDC_HOSTED isn't set. We wrap around these to augment tyhem for some things. The idea was that we can't control GCC, so we'd do it in a header. But if GCC is excluded we can just update clang, since those are the only supported compilers right now.

@nickdesaulniers
Copy link
Member Author

nickdesaulniers commented Jan 23, 2024

Where is include_next that you're referring to?

Perhaps you were referring to:

#include_next <limits.h>

Which indeed does pull in <limits.h> via an include_next if __STDC_HOSTED__. It then steamrolls these definitions via a large series of #undefs.

It seems that we also set -ffreestanding for fullbuild mode. (Which is highly suspect to me)

if(LLVM_LIBC_FULL_BUILD)
# Only add -ffreestanding flag in full build mode.
list(APPEND compile_options "-ffreestanding")

The idea was that we can't control GCC, so we'd do it in a header.

That's another approach we could take, which #78887 very nearly does, except:

  1. it still uses include_next to include...who knows what (include_next depends on the compiler search path at compile time)...
  2. it doesn't remove existing users of <limits.h>

I think I'd be ok with that approach if 1 and 2 were addressed as well in the same PR. (or a good reason for NOT doing either was provided)

Personally, I have a weak preference for "relying on the compiler (and it's resource dir)" a la this PR. But I could be convinced to not use ANY external dependency and just define these ourselves.


FWIW, clang's preprocessor also generates some of these defines. Example:

Builder.defineMacro("__CHAR_BIT__", Twine(TI.getCharWidth()));
Builder.defineMacro("__BOOL_WIDTH__", Twine(TI.getBoolWidth()));
Builder.defineMacro("__SHRT_WIDTH__", Twine(TI.getShortWidth()));
Builder.defineMacro("__INT_WIDTH__", Twine(TI.getIntWidth()));
Builder.defineMacro("__LONG_WIDTH__", Twine(TI.getLongWidth()));
Builder.defineMacro("__LLONG_WIDTH__", Twine(TI.getLongLongWidth()));
size_t BitIntMaxWidth = TI.getMaxBitIntWidth();
assert(BitIntMaxWidth <= llvm::IntegerType::MAX_INT_BITS &&
"Target defined a max bit width larger than LLVM can support!");
assert(BitIntMaxWidth >= TI.getLongLongWidth() &&
"Target defined a max bit width smaller than the C standard allows!");
Builder.defineMacro("__BITINT_MAXWIDTH__", Twine(BitIntMaxWidth));
DefineTypeSize("__SCHAR_MAX__", TargetInfo::SignedChar, TI, Builder);
DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
DefineTypeSizeAndWidth("__WCHAR", TI.getWCharType(), TI, Builder);
DefineTypeSizeAndWidth("__WINT", TI.getWIntType(), TI, Builder);
DefineTypeSizeAndWidth("__INTMAX", TI.getIntMaxType(), TI, Builder);
DefineTypeSizeAndWidth("__SIZE", TI.getSizeType(), TI, Builder);
DefineTypeSizeAndWidth("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
DefineTypeSizeAndWidth("__PTRDIFF", TI.getPtrDiffType(LangAS::Default), TI,
Builder);
DefineTypeSizeAndWidth("__INTPTR", TI.getIntPtrType(), TI, Builder);
DefineTypeSizeAndWidth("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_INT__", TI.getIntWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_LONG__", TI.getLongWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_LONG_DOUBLE__",TI.getLongDoubleWidth(),TI,Builder);
DefineTypeSizeof("__SIZEOF_LONG_LONG__", TI.getLongLongWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_POINTER__", TI.getPointerWidth(LangAS::Default),
TI, Builder);
DefineTypeSizeof("__SIZEOF_SHORT__", TI.getShortWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_PTRDIFF_T__",
TI.getTypeWidth(TI.getPtrDiffType(LangAS::Default)), TI,
Builder);
DefineTypeSizeof("__SIZEOF_SIZE_T__",
TI.getTypeWidth(TI.getSizeType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WCHAR_T__",
TI.getTypeWidth(TI.getWCharType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WINT_T__",
TI.getTypeWidth(TI.getWIntType()), TI, Builder);
if (TI.hasInt128Type())
DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
DefineFmt("__INTMAX", TI.getIntMaxType(), TI, Builder);
Builder.defineMacro("__INTMAX_C_SUFFIX__",
TI.getTypeConstantSuffix(TI.getIntMaxType()));
DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
DefineFmt("__UINTMAX", TI.getUIntMaxType(), TI, Builder);

(besides the header file I linked to above)

@lntue
Copy link
Contributor

lntue commented Jan 24, 2024

The idea was that we can't control GCC, so we'd do it in a header.

That's another approach we could take, which #78887 very nearly does, except:

  1. it still uses include_next to include...who knows what (include_next depends on the compiler search path at compile time)...
  2. it doesn't remove existing users of <limits.h>

I think I'd be ok with that approach if 1 and 2 were addressed as well in the same PR. (or a good reason for NOT doing either was provided)

I could definitely include 2 to #78887. On the other hand, the main reason I added #include_next <limits.h> just in-case they the environment headers provide other extra macros that we don't have (yet). We can remove the #include_next there if you think it is unnecessary.

Personally, I have a weak preference for "relying on the compiler (and it's resource dir)" a la this PR. But I could be convinced to not use ANY external dependency and just define these ourselves.

FWIW, clang's preprocessor also generates some of these defines. Example:

Builder.defineMacro("__CHAR_BIT__", Twine(TI.getCharWidth()));
Builder.defineMacro("__BOOL_WIDTH__", Twine(TI.getBoolWidth()));
Builder.defineMacro("__SHRT_WIDTH__", Twine(TI.getShortWidth()));
Builder.defineMacro("__INT_WIDTH__", Twine(TI.getIntWidth()));
Builder.defineMacro("__LONG_WIDTH__", Twine(TI.getLongWidth()));
Builder.defineMacro("__LLONG_WIDTH__", Twine(TI.getLongLongWidth()));
size_t BitIntMaxWidth = TI.getMaxBitIntWidth();
assert(BitIntMaxWidth <= llvm::IntegerType::MAX_INT_BITS &&
"Target defined a max bit width larger than LLVM can support!");
assert(BitIntMaxWidth >= TI.getLongLongWidth() &&
"Target defined a max bit width smaller than the C standard allows!");
Builder.defineMacro("__BITINT_MAXWIDTH__", Twine(BitIntMaxWidth));
DefineTypeSize("__SCHAR_MAX__", TargetInfo::SignedChar, TI, Builder);
DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
DefineTypeSizeAndWidth("__WCHAR", TI.getWCharType(), TI, Builder);
DefineTypeSizeAndWidth("__WINT", TI.getWIntType(), TI, Builder);
DefineTypeSizeAndWidth("__INTMAX", TI.getIntMaxType(), TI, Builder);
DefineTypeSizeAndWidth("__SIZE", TI.getSizeType(), TI, Builder);
DefineTypeSizeAndWidth("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
DefineTypeSizeAndWidth("__PTRDIFF", TI.getPtrDiffType(LangAS::Default), TI,
Builder);
DefineTypeSizeAndWidth("__INTPTR", TI.getIntPtrType(), TI, Builder);
DefineTypeSizeAndWidth("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_INT__", TI.getIntWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_LONG__", TI.getLongWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_LONG_DOUBLE__",TI.getLongDoubleWidth(),TI,Builder);
DefineTypeSizeof("__SIZEOF_LONG_LONG__", TI.getLongLongWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_POINTER__", TI.getPointerWidth(LangAS::Default),
TI, Builder);
DefineTypeSizeof("__SIZEOF_SHORT__", TI.getShortWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_PTRDIFF_T__",
TI.getTypeWidth(TI.getPtrDiffType(LangAS::Default)), TI,
Builder);
DefineTypeSizeof("__SIZEOF_SIZE_T__",
TI.getTypeWidth(TI.getSizeType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WCHAR_T__",
TI.getTypeWidth(TI.getWCharType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WINT_T__",
TI.getTypeWidth(TI.getWIntType()), TI, Builder);
if (TI.hasInt128Type())
DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
DefineFmt("__INTMAX", TI.getIntMaxType(), TI, Builder);
Builder.defineMacro("__INTMAX_C_SUFFIX__",
TI.getTypeConstantSuffix(TI.getIntMaxType()));
DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
DefineFmt("__UINTMAX", TI.getUIntMaxType(), TI, Builder);

(besides the header file I linked to above)

Clang and GCC both provide various of those definitions, but which ones they provide do vary depending on their versions and the platforms. So I think we can use C23-compliance as a reason and a selling point to just provide a complete limits.h header, consistent across compilers+versions+supported platforms?

There is only 1 constant that confuses me is MB_LEN_MAX, which seems to be 1 for clang's header, 16 for glibc, and 4 for musl...

@nickdesaulniers
Copy link
Member Author

nickdesaulniers commented Jan 24, 2024

On the other hand, the main reason I added #include_next <limits.h> just in-case they the environment headers provide other extra macros that we don't have (yet). We can remove the #include_next there if you think it is unnecessary.

More specifically, I worry about include_next is even referring to, particularly if it's glibc's limits.h. Then we're mixing our headers with glibc's. Perhaps that unavoidable for full build mode.

If you remove #include_next <limits.h> from #78887, does it still work? If so, let's remove it, just so we have certainty about what's getting included at runtime.

As for other extra macros; I'd kind of like to know what they are (if any). I think it's better to exclude them for now, then add them when we observed an issue specific to not including them. Then we can have well formed justification for why we include them, rather than pull in headers based on the hope that they contain something that might be helpful (but who knows what else).

There is only 1 constant that confuses me is MB_LEN_MAX, which seems to be 1 for clang's header, 16 for glibc, and 4 for musl...

Does MB stand for multi-byte characters? Sticking to the point above, I don't mind leaving it out until it becomes a problem. That can get fixed then. Right now, I think it's just some of the LLONG_MAX integer macros that are used in our tests that are relevant to our current use cases. We can fix that in the future when we have more customers interested in multi-byte char support.

@nickdesaulniers
Copy link
Member Author

Prefer #78887

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants