Skip to content

offsetof() is not constant in clang-cl #59689

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

Closed
danakj opened this issue Dec 24, 2022 · 14 comments · Fixed by #127568
Closed

offsetof() is not constant in clang-cl #59689

danakj opened this issue Dec 24, 2022 · 14 comments · Fixed by #127568
Labels
clang-cl `clang-cl` driver. Don't use for other compiler parts

Comments

@danakj
Copy link
Contributor

danakj commented Dec 24, 2022

I use offsetof in a template parameter, this works on all compilers (Clang, MSVC, GCC) except clang-cl.

error: non-type template argument is not a constant expression

C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\stddef.h(47,31): note: 
      expanded from macro 'offsetof'
  ...offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))    
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    

Obviously reinterpret_cast is not constant evaluable. So I guess MSVC provides a builtin, but clang-cl does not?

@danakj
Copy link
Contributor Author

danakj commented Dec 24, 2022

Simple repro:

struct S { int i; };
constexpr auto x = offsetof(S, i);
error: 
      constexpr variable 'x' must be initialized by a constant expression
constexpr auto x = offsetof(S, i);
               ^   ~~~~~~~~~~~~~~
note: cast that
      performs the conversions of a reinterpret_cast is not allowed in a constant       
      expression
constexpr auto x = offsetof(S, i);
                   ^

@danakj
Copy link
Contributor Author

danakj commented Dec 24, 2022

danakj added a commit to danakj/subspace that referenced this issue Dec 24, 2022
Since offsetof() is not a constant expression on clang-cl,
though it is on other compilers.

llvm/llvm-project#59689
danakj added a commit to danakj/subspace that referenced this issue Dec 24, 2022
Since offsetof() is not a constant expression on clang-cl,
though it is on other compilers.

llvm/llvm-project#59689
danakj added a commit to chromium/subspace that referenced this issue Dec 24, 2022
Since offsetof() is not a constant expression on clang-cl,
though it is on other compilers.

llvm/llvm-project#59689
@EugeneZelenko EugeneZelenko added clang-cl `clang-cl` driver. Don't use for other compiler parts and removed new issue labels Dec 24, 2022
@efriedma-quic
Copy link
Collaborator

efriedma-quic commented Dec 24, 2022

How are you invoking clang-cl? In the past, we made this work by making clang-cl use its own stddef.h, which has the proper definition of offsetof.

Apparently recent SDKs guard the definition of offsetof with a define _CRT_USE_BUILTIN_OFFSETOF; if you define that, it uses __builtin_offsetof just like clang's stddef.h. Maybe clang-cl should be defining that.

@danakj
Copy link
Contributor Author

danakj commented Dec 24, 2022

I am invoking it by constructing a ClangTool and invoking tool.buildASTs(), on Windows with LLVM/Clang and my tool compiled by MSVC.

I am running my tool against a compile database, and here's an example CommandLine from the compile database:

C:\PROGRA~1\MICROS~2\2022\COMMUN~1\VC\Tools\MSVC\1434~1.319\bin\Hostx86\x64\cl.exe \
    --driver-mode=cl /nologo /TP /DWIN32 /D_WINDOWS /GR /EHsc /Zi /Ob0 /Od /RTC1 -MDd \
    /Zc:preprocessor /wd5105 -std:c++20 /Fomy_input_file.obj /FdTARGET_COMPILE_PDB /FS \
    -c my_input_file.cc

@danakj
Copy link
Contributor Author

danakj commented Dec 24, 2022

Passing it to MSVC with /D_CRT_USE_BUILTIN_OFFSETOF makes the compiler unhappy.

[build] command line(1): error C2220: the following warning is treated as an error
[build] command line(1): warning C4117: macro name '_CRT_USE_BUILTIN_OFFSETOF' is reserved, '#define' ignored

Since I am using MSVC that means it will not be able to appear in my compile database. I will need to

  1. insert in my library's CMakelists.txt only if building with clang-cl (so that clang-cl works with the lib)
  2. also insert it in my tool unconditionally since the compdb may not be created by clang-cl.

It'd be nice if clang-cl did define that itself, if that's the answer.

@danakj
Copy link
Contributor Author

danakj commented Dec 24, 2022

I do confirm that adding /D_CRT_USE_BUILTIN_OFFSETOF to the command line inside my ClangTool does resolve this for my tool, would be great to see clang-cl address this itself.

danakj added a commit to danakj/subspace that referenced this issue Dec 24, 2022
We need to define `_CRT_USE_BUILTIN_OFFSETOF ` when compiling
with clang-cl, both for subspace (and its dependents) and for
the CIR tool.

The define works around the clang-cl issue
llvm/llvm-project#59689 without requiring
code changes.
danakj added a commit to chromium/subspace that referenced this issue Dec 24, 2022
We need to define `_CRT_USE_BUILTIN_OFFSETOF ` when compiling
with clang-cl, both for subspace (and its dependents) and for
the CIR tool.

The define works around the clang-cl issue
llvm/llvm-project#59689 without requiring
code changes.
@efriedma-quic
Copy link
Collaborator

I suspect your tool isn't constructing the clang command-line correctly. Does it work if you invoke clang-cl directly? What's the output of if you pass "/clang:-###"?

See also #58918

@danakj
Copy link
Contributor Author

danakj commented Dec 25, 2022

Thanks. I'm not really constructing a command line myself, but it does seem like executing clang-cl does something different than ClangTool does.

I am just giving the compile db to ClangTool and giving it the path of one of the source files in the compile db. Clang figures out the command line from there.

However, when I run the clang-cl binary (replacing cl.exe with clang-cl.exe in the compile db's command line) it works correctly with offsetof(). So, perhaps this is a bug in ClangTool?

Actual code:

void f(const clang::tooling::CompilationDatabase& compdb,
       std::vector<std::string> paths,
       llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs) noexcept {
  auto tool = clang::tooling::ClangTool(
      compdb, paths, std::make_shared<clang::PCHContainerOperations>(),
      std::move(fs));

  auto adj = [](auto args, llvm::StringRef Filename) {
    // Clang-cl doesn't understand this argument, but it may appear in the
    // command-line for MSVC in C++20 codebases.
    std::erase(args, "/Zc:preprocessor");

    // TODO: https://github.com/llvm/llvm-project/issues/59689 clang-cl requires
    // this define in order to use offsetof() from constant expressions.
    args.push_back("/D_CRT_USE_BUILTIN_OFFSETOF");

    return std::move(args);
  };
  tool.appendArgumentsAdjuster(adj);

  auto asts = std::vector<std::unique_ptr<clang::ASTUnit>>();
  tool.buildASTs(asts);

@efriedma-quic
Copy link
Collaborator

That sounds like the tool is failing to find the builtin include directory correctly. So clang-cl itself finds the correct directory, but clangtool somehow doesn't. So clang-cl uses its own stddef.h, but clangtool fails to find it. And instead of printing a diagnostic, it falls back to the SDK's stddef.h. Seems very similar to #58918.

@Lectem
Copy link

Lectem commented Dec 30, 2022

Justed wanted to say I encountered the exact same issue with clang-tidy. See microsoft/STL#3311
EDIT: Seems the upstream clang-tidy already has this fixed. (checked using LLVM version 15.0.6)

@tychedelia
Copy link

Ran into this using a libclang.dll retrieved via the Visual Studio 2022 installer just today, so presumably fix hasn't worked it's way there yet. Passing /D_CRT_USE_BUILTIN_OFFSETOF to clang solved this for me.

Keywords for the webcrawlers:
rust autocxx cxx cc mvsc clang static_assert offsetof

error: static assertion expression is not an integral constant expression

note: cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression

@CaseyCarter
Copy link
Member

Visual Studio 2022 should be on track as of version 17.7 preview 3. We (MSVC) didn't notice that LLVM 16 changed clang's expected installation layout, so our repackaging put the override headers in the wrong place.

@JCash
Copy link

JCash commented Nov 27, 2023

I can also confirm that the /D_CRT_USE_BUILTIN_OFFSETOF worked as a workaround for me.

I build on Linux, using clang-17, using this command line (here without the workaround):

clang++ -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -D__STDC_LIMIT_MACROS -DWINVER=0x0600 -DWIN32 -DNOMINMAX -target i386-pc-win32-msvc -m32 -O2 -g -gcodeview -Wall -Werror=format -fvisibility=hidden -nostdinc++ -std=c++17 -fno-rtti -fno-exceptions  -nostdinc++ -isystem /opt/platformsdk/Win32/MicrosoftVisualStudio2022/VC/Tools/MSVC/14.37.32822/atlmfc/include -isystem /opt/platformsdk/Win32/WindowsKits/10/Include/10.0.20348.0/ucrt -isystem /opt/platformsdk/Win32/WindowsKits/10/Include/10.0.20348.0/winrt -isystem /opt/platformsdk/Win32/WindowsKits/10/Include/10.0.20348.0/um -isystem /opt/platformsdk/Win32/WindowsKits/10/Include/10.0.20348.0/shared  -Ibuild/upload/ -Iupload/  -I/var/extender/sdk/799a9e73dc2f3518387e3eb5a1a77f98c002e019/defoldsdk/include -I/var/extender/sdk/799a9e73dc2f3518387e3eb5a1a77f98c002e019/defoldsdk/sdk/include -I/var/extender/sdk/799a9e73dc2f3518387e3eb5a1a77f98c002e019/defoldsdk/ext/include -Iupload/src  upload/src/test.cpp -c -o build/test.cpp_8.o

Smertig added a commit to Smertig/rscpp-command-line-test that referenced this issue May 18, 2024
* There's an issue with _CRT_USE_BUILTIN_OFFSETOF: llvm/llvm-project#59689
@frederick-vs-ja
Copy link
Contributor

Looks like that Clang (clang-cl) should just predefine _CRT_USE_BUILTIN_OFFSETOF. MSVC predefines the macro (as 1) at least since 19.14 (Godbolt link).

frederick-vs-ja added a commit that referenced this issue Mar 13, 2025
…127568)

This patch makes Clang predefine `_CRT_USE_BUILTIN_OFFSETOF` in
MS-compatible modes. The macro can make the `offsetof` provided by MS
UCRT's `<stddef.h>` to select the `__builtin_offsetof` version, so with
it Clang (Clang-cl) can directly consume UCRT's `offsetof`.

MSVC predefines the macro as `1` since at least VS 2017 19.14, but I
think it's also OK to define it in "older" compatible modes.

Fixes #59689.
frederik-h pushed a commit to frederik-h/llvm-project that referenced this issue Mar 18, 2025
…lvm#127568)

This patch makes Clang predefine `_CRT_USE_BUILTIN_OFFSETOF` in
MS-compatible modes. The macro can make the `offsetof` provided by MS
UCRT's `<stddef.h>` to select the `__builtin_offsetof` version, so with
it Clang (Clang-cl) can directly consume UCRT's `offsetof`.

MSVC predefines the macro as `1` since at least VS 2017 19.14, but I
think it's also OK to define it in "older" compatible modes.

Fixes llvm#59689.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang-cl `clang-cl` driver. Don't use for other compiler parts
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants