steakhal wrote:

Hey, I know it's kinda late to report this, but it took me some time to debug 
this issue downstream.
@HerrCai0907 @vbvictor

The `clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp` 
test breaks when building on MacOS with the 
`CMAKE_OSX_ARCHITECTURES='x86_64;arm64;arm64e'` make option.

Here are the exact steps to reproduce the test failure:
```
git checkout 292c9e3d198249e329be355d1513484a559c2f8a
xcrun cmake  -S llvm -B build/tmp 
-DCMAKE_OSX_ARCHITECTURES='x86_64;arm64;arm64e' 
-DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra'  -DLLVM_ENABLE_ZSTD=OFF 
-DCMAKE_BUILD_TYPE=Release
xcrun ninja -C build/tmp clang-tidy FileCheck split-file
xcrun build/tmp/bin/llvm-lit -a 
clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp
```

This should result the following test failure:
```
# | error: unable to handle compilation, expected exactly one compiler job in ' 
"/Applications/XCODE-REDACTED/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++"
 "-cc1" "-triple" "x86_64-apple-macosxREDACTED" "-O2" 
"-Wundef-prefix=TARGET_OS_" "-Werror=undef-prefix" 
"-Wdeprecated-objc-isa-usage" "-Werror=deprecated-objc-isa-usage" 
"-fsyntax-only" "-disable-free" "-clear-ast-before-backend" "-main-file-name" 
"main.cpp" "-mrelocation-model" "pic" "-pic-level" "2" "-mframe-pointer=all" 
"-ffp-contract=on" "-fno-rounding-math" "-funwind-tables=2" 
"-target-sdk-version=REDACTED" 
"-fcompatibility-qualified-id-block-type-checking" "-fvisibili
ty-inlines-hidden-static-local-var" "-fdefine-target-os-macros" 
"-fno-modulemap-allow-subdirectory-search" "-tune-cpu" "generic" 
"-gkey-instructions" "-debug-info-kind=standalone" "-dwarf-vers
ion=5" "-debugger-tuning=lldb" "-fdebug-compilation-dir=build/tmp" 
"-target-linker-version" "REDACTED" "-fcoverage-compilation-dir=build/custom" 
"-isysroot" "/Library/Developer/CommandLineTools/SDKs/MacOSXREDACTED" "-D" 
"GTEST_HAS_RTTI=0" "-D" "LLVM_EXPORTS" "-D" "_DEBUG" "-D" "_GLIBCXX_ASSERTIONS 
... "; "/Applications/XCODE..."; "/Applications/XCODE..."; ' 
[clang-diagnostic-error]
```

From what I could see is that since `CMAKE_OSX_ARCHITECTURES` is set, make will 
generate a `build/tmp/compile_commands.json` containing build commands building 
fat archives, holding multiple architectures such as `'x86_64;arm64;arm64e'`. 
This is materialised in the commands as multiple `-arch x86_64 -arch arm64 
-arch arm64e`
For example:
```
{
  "directory": "build/tmp",
  "command": 
"/Applications/Xcode-REDACTED/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
 -DGTEST_HAS_RTTI=0 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS 
-D__STDC_LIMIT_MACROS -Ibuild/tmp/lib/Demangle -Illvm/lib/Demangle 
-Ibuild/tmp/include -Illvm/include  -fPIC -fvisibility-inlines-hidden 
-Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra 
-Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers 
-pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough 
-Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor 
-Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion 
-Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported 
-fdiagnostics-color -O3 -DNDEBUG -std=c++17 -arch x86_64 -arch arm64 -arch 
arm64e -isysroot 
/Library/Developer/CommandLineTools/SDKs/MacOSXREDACTED-fno-exceptions 
-funwind-tables -fno-rtti -o 
lib/Demangle/CMakeFiles/LLVMDemangle.dir/Demangle.cpp.o -c 
llvm/lib/Demangle/Demangle.cpp",
  "file": "llvm/lib/Demangle/Demangle.cpp",
  "output": "lib/Demangle/CMakeFiles/LLVMDemangle.dir/Demangle.cpp.o"
},...
```

What puzzled me for a while was the following: how could this possibly affect 
the outcome of the 
`clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp` test.

Well, as it turns out, in the test, as tidy starts up, it will look for a 
`compile_commands.json`. And start looking from the test file, which is a VFS 
path: 
`build/tmp/tools/clang/tools/extra/test/clang-tidy/infrastructure/Output/custom-query-check.cpp.tmp/subdir/main.cpp`.
As it doesn't find the compile_commands.json near that file, it will start 
walking up the path, until it finds one.
As it happens, the first compile_commands.json file is at 
`build/tmp/compile_commands.json` that doesn't have an exact entry for the 
desired `..../subdir/main.cpp`, so the 
`InterpolatingCompilationDatabase::chooseProxy()` will try to find a suitable 
candidate by "scoring" them. For us, it basically means it will randomly pick 
one, and that one will have multiple `-arch` options in the command.

So `tidy` would eventually go into and trigger the 
`diag::err_fe_expected_compiler_job` warning: `"unable to handle compilation, 
expected exactly one compiler job in '%0'"` inside `getCC1Arguments()` in 
`clang/lib/Tooling/Tooling.cpp`.

I am not exactly sure how to fix this, but a workaround I had in mind was to 
supply a mock `compile_commands.json` alongside the test so that it picks that 
up in the `CompilationDatabase::autoDetectFromSource()`. However, the path walk 
uses the `JSONCompilationDatabase::loadFromFile()` which in turn uses 
`llvm::MemoryBuffer::getFile()` which does not honour VFS, so using the 
`vfsoverlay` trick from the test is not suitable for this.
However, the test could be transformed to use `split-file` and also inject a 
mock `compile_commands.json`.
This works and passes for me, using `split-file`:

```
// sed command does not work as-is on Windows.
// UNSUPPORTED: system-windows
// REQUIRES: custom-check

// RUN: rm -rf %t
// RUN: split-file %s %t

// RUN: sed -e "s:OUT_DIR:%t:g" %t/compile_commands.json.template > 
%t/compile_commands.json

// RUN: mkdir %t/subdir
// RUN: mkdir %t/subdir-override
// RUN: mkdir %t/subdir-empty
// RUN: mkdir %t/subdir-append

// RUN: cp %t/main.cpp %t/subdir/main.cpp
// RUN: cp %t/main.cpp %t/subdir-override/main.cpp
// RUN: cp %t/main.cpp %t/subdir-empty/main.cpp
// RUN: cp %t/main.cpp %t/subdir-append/main.cpp

// RUN: clang-tidy --experimental-custom-checks %t/main.cpp 
-checks='-*,custom-*' | FileCheck %t/main.cpp --check-prefix=CHECK-SAME-DIR
// RUN: clang-tidy --experimental-custom-checks %t/subdir/main.cpp 
-checks='-*,custom-*' | FileCheck %t/main.cpp --check-prefix=CHECK-SUB-DIR-BASE
// RUN: clang-tidy --experimental-custom-checks %t/subdir-override/main.cpp 
-checks='-*,custom-*' | FileCheck %t/main.cpp 
--check-prefix=CHECK-SUB-DIR-OVERRIDE
// RUN: clang-tidy --experimental-custom-checks %t/subdir-empty/main.cpp 
-checks='-*,custom-*' --allow-no-checks | FileCheck %t/main.cpp 
--check-prefix=CHECK-SUB-DIR-EMPTY
// RUN: clang-tidy --experimental-custom-checks %t/subdir-append/main.cpp 
-checks='-*,custom-*' | FileCheck %t/main.cpp 
--check-prefix=CHECK-SUB-DIR-APPEND
// RUN: clang-tidy --experimental-custom-checks %t/subdir-append/main.cpp 
-checks='-*,custom-*' --list-checks | FileCheck %t/main.cpp 
--check-prefix=LIST-CHECK
// RUN: clang-tidy --experimental-custom-checks %t/subdir-append/main.cpp 
-checks='-*,custom-*' --dump-config | FileCheck %t/main.cpp 
--check-prefix=DUMP-CONFIG


//--- compile_commands.json.template
[{
  "directory": "OUT_DIR",
  "command": "clang++ main.cpp -fsyntax-only",
  "file": "main.cpp",
  "output": ""
}]

//--- .clang-tidy
CustomChecks:
  - Name: avoid-long-type
    Query: |
      match varDecl(
          hasType(asString("long")),
          hasTypeLoc(typeLoc().bind("long"))
      )
    Diagnostic:
      - BindName: long
        Message: use 'int' instead of 'long'
        Level: Warning

//--- subdir-override/.clang-tidy
CustomChecks:
  - Name: avoid-long-type
    Query: |
      match varDecl(
          hasType(asString("long")),
          hasTypeLoc(typeLoc().bind("long"))
      )
    Diagnostic:
      - BindName: long
        Message: use 'int' instead of 'long' override
        Level: Warning

//--- subdir-empty/.clang-tidy
InheritParentConfig: false

//--- subdir-append/.clang-tidy
InheritParentConfig: true
CustomChecks:
  - Name: function-decl
    Query: match functionDecl().bind("func")
    Diagnostic:
      - BindName: func
        Message: find function decl
        Level: Warning

//--- main.cpp
long V;
// CHECK-SAME-DIR: [[@LINE-1]]:1: warning: use 'int' instead of 'long' 
[custom-avoid-long-type]
// CHECK-SUB-DIR-BASE: [[@LINE-2]]:1: warning: use 'int' instead of 'long' 
[custom-avoid-long-type]
// CHECK-SUB-DIR-OVERRIDE: [[@LINE-3]]:1: warning: use 'int' instead of 'long' 
override [custom-avoid-long-type]
// CHECK-SUB-DIR-EMPTY: No checks enabled.
// CHECK-SUB-DIR-APPEND: [[@LINE-5]]:1: warning: use 'int' instead of 'long' 
[custom-avoid-long-type]

void f();
// CHECK-SUB-DIR-APPEND: [[@LINE-1]]:1: warning: find function decl 
[custom-function-decl]

// LIST-CHECK: Enabled checks:
// LIST-CHECK:   custom-avoid-long-type
// LIST-CHECK:   custom-function-decl

// DUMP-CONFIG: CustomChecks:
// DUMP-CONFIG: - Name: avoid-long-type
// DUMP-CONFIG:   Query: |
// DUMP-CONFIG:     match varDecl(
// DUMP-CONFIG:       hasType(asString("long")),
// DUMP-CONFIG:       hasTypeLoc(typeLoc().bind("long"))
// DUMP-CONFIG:     )
// DUMP-CONFIG:   Diagnostic:
// DUMP-CONFIG:    - BindName: long
// DUMP-CONFIG:      Message: |
// DUMP-CONFIG:           use 'int' instead of 'long'
// DUMP-CONFIG:      Level:           Warning
// DUMP-CONFIG: - Name: function-decl
// DUMP-CONFIG:   Query: |
// DUMP-CONFIG:     match functionDecl().bind("func")
// DUMP-CONFIG:   Diagnostic:
// DUMP-CONFIG:    - BindName: func
// DUMP-CONFIG:      Message: |
// DUMP-CONFIG:        find function decl
// DUMP-CONFIG:   Level: Warning
```

Despite patching the test would sidestep this failure, I definitely think that 
we should instead figure out why did this auto compile-command.json discovery 
kick in because that made this debugging experience terrible; so I think there 
is some room for improvement here.

https://github.com/llvm/llvm-project/pull/131804
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to