Skip to content

Fails to compile with Clang in c++20 mode when constexpr is disabled #4545

@SnapperTT

Description

@SnapperTT

I need to disable constexpr because I am using a custom string class:

#define FMT_USE_CONSTEXPR 0
#define FMT_USE_CONSTEVAL 0

The problem now is that this does not disable FMT_USE_CONSTEVAL. The fix for this is is to not define FMT_USE_CONSTEVAL if it is already defined:

#ifndef FMT_USE_CONSTEVAL <------------------ this change
	#if !defined(__cpp_lib_is_constant_evaluated)
	#  define FMT_USE_CONSTEVAL 0
	#elif FMT_CPLUSPLUS < 201709L
	#  define FMT_USE_CONSTEVAL 0
	#elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10
	#  define FMT_USE_CONSTEVAL 0
	#elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000
	#  define FMT_USE_CONSTEVAL 0
	#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L
	#  define FMT_USE_CONSTEVAL 0  // consteval is broken in Apple clang < 14.
	#elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929
	#  define FMT_USE_CONSTEVAL 0  // consteval is broken in MSVC VS2019 < 16.10.
	#elif defined(__cpp_consteval)
	#  define FMT_USE_CONSTEVAL 1
	#elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101
	#  define FMT_USE_CONSTEVAL 1
	#else
	#  define FMT_USE_CONSTEVAL 0
	#endif
#endif

Finally is_constant_evaluated ignores the value of FMT_USE_CONSTEXPR. This can be fixed by short circuiting it:

constexpr auto is_constant_evaluated(bool default_value = false) noexcept
    -> bool {
// is_constant_evaluated is never true if we're not using constexpr
#if !FMT_USE_CONSTEXPR
	return false;
#endif
// Workaround for incompatibility between clang 14 and libstdc++ consteval-based
// std::is_constant_evaluated: https://github.com/fmtlib/fmt/issues/3247.
#if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \
    (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500)
  ignore_unused(default_value);
  return __builtin_is_constant_evaluated();
#elif defined(__cpp_lib_is_constant_evaluated)
  ignore_unused(default_value);
  return std::is_constant_evaluated();
#else
  return default_value;
#endif
}

This allows it to compile and run

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions