Skip to content

Conversation

@cor3ntin
Copy link
Contributor

@cor3ntin cor3ntin commented Oct 2, 2025

In the standard, constraint satisfaction checking is done on the normalized form of a constraint.

Clang instead substitutes on the non-normalized form, which causes us to report substitution failures in template arguments or concept ids, which is non-conforming but unavoidable without a parameter mapping

This patch normalizes before satisfaction checking. However, we preserve concept-id nodes in the normalized form, solely for diagnostics purposes.

This addresses #61811 and related concepts conformance bugs, ideally to make the remaining implementation of concept template parameters easier

Fixes #135190
Fixes #61811

Co-authored-by: Younan Zhang [email protected]

@cor3ntin
Copy link
Contributor Author

@zmodem Thanks, I'll investigate.

Note that we expected some performance degradation on very concept heavy codebase without having a good way to quantify it - and it's not clear how much of that we can claw back, but we will certainly try to improve that as much as we can - I certainly agree that 10-15% is a lot

There are still places where our concept implementations is non-conforming so in theory we would have to make the performance worse still, but these non-conformances are less observables so we'll try to focus on improving performances before doing anything else to our concepts implementation.

@rnk
Copy link
Collaborator

rnk commented Oct 20, 2025

I discussed this with Hans today, and we think one way to evaluate the performance impact would be to bootstrap clang itself with C++20 enabled. I think Chromium, and probably most C++ code in the wild, isn't using C++20 concepts heavily, and is mostly picking them up through libc++.

I really would not want to eat a 16% C++ compile time regression on normal C++ code. As a point of comparison, we're using 32-bit source locations to avoid a 4% peak memory usage increase with 0% measurable regression, which is very conservative.

It's hard, though, since it's a performance vs conformance (arguably correctness) tradeoff, it's just not a correctness regression, which we usually weight very highly when making tradeoff decisions. :)

cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Oct 22, 2025
…ion.

When establishing constraint satisfaction, we were
building expressions even for compound constraint,

This is unecessary extra work that acount for ~20% of the
performance regression observed here

llvm#161671 (comment)
cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Oct 22, 2025
…ion.

When establishing constraint satisfaction, we were
building expressions even for compound constraint,

This is unecessary extra work that acount for ~20% of the
performance regression observed here

llvm#161671 (comment)
cor3ntin added a commit that referenced this pull request Oct 22, 2025
…tion (#164611)

When establishing constraint satisfaction, we were building expressions
even for compound constraint,

This is unnecessary extra work that accounts for ~20% of the performance
regression observed here
#161671 (comment)
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 22, 2025
…ng satisfaction (#164611)

When establishing constraint satisfaction, we were building expressions
even for compound constraint,

This is unnecessary extra work that accounts for ~20% of the performance
regression observed here
llvm/llvm-project#161671 (comment)
@rupprecht
Copy link
Collaborator

I bisected a breakage to this commit, and while I'm still unsure whether the code is breaking is valid or not, it's behaving unexpectedly: the breakage is affected by other template instantiations. I suspect something is wrong with this patch. Reduced/filed as #164750.

@zyn0217
Copy link
Contributor

zyn0217 commented Oct 23, 2025

I bisected a breakage to this commit, and while I'm still unsure whether the code is breaking is valid or not, it's behaving unexpectedly: the breakage is affected by other template instantiations. I suspect something is wrong with this patch. Reduced/filed as #164750.

@rupprecht #164777 will fix it. Thanks for the heads up!

@zmodem
Copy link
Collaborator

zmodem commented Oct 23, 2025

Here's another example TU. perf stat -r5 shows a 27% regression here. 72616c5 does not seem to make much difference.

clang -cc1 -triple x86_64-unknown-linux-gnu -O0 -emit-obj -mrelocation-model pic -pic-level 2 -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse3 -tune-cpu generic -debug-info-kind=constructor -dwarf-version=4 -debugger-tuning=gdb -ggnu-pubnames -gsimple-template-names=simple -mllvm -generate-arange-section -debug-forward-template-params  -std=c++20 -fdeprecated-macro -fvisibility=hidden -fvisibility-inlines-hidden -fwrapv -fwrapv-pointer -pthread -stack-protector 1 -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -Qn -fuse-ctor-homing -fcomplete-member-pointers -faddrsig -x c++ /tmp/inspector_style_resolver.ii -w

inspector_style_resolver.ii.gz

@zmodem
Copy link
Collaborator

zmodem commented Oct 24, 2025

one way to evaluate the performance impact would be to bootstrap clang itself with C++20 enabled.

I looked into this, building a stage0 clang and libc++ configured with:

$ cmake -GNinja -Bstage0 -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=OFF -DLLVM_ENABLE_PROJECTS=clang -DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind' -DLLVM_TARGETS_TO_BUILD=X86 llvm/

and then using that to do a debug shared-library build of clang in c++20 mode:

$ CC=$PWD/stage0/bin/clang CXX=$PWD/stage0/bin/clang++ CXXFLAGS=-stdlib=libc++ cmake -GNinja -Bstage1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=20 -DLLVM_USE_LINKER=lld -DBUILD_SHARED_LIBS=ON -DLLVM_ENABLE_PROJECTS=clang -DLLVM_TARGETS_TO_BUILD=X86 llvm/
$ mkdir -p stage1/lib && cp stage0/lib/x86_64-unknown-linux-gnu/*.so* stage1/lib/
$ rm -f stage1/.ninja_log && time ninja -C stage1 clang

The increase from this change is small but measurable: about 5 CPU-minutes, or 1.5 %.

I suppose it makes sense that the difference is smaller, since this codebase has no use of concepts at all besides via the STL, as opposed to Chromium which does seem to have a fair amount of concepts use in its base library, Abseil and so on.


I'm not sure how to proceed here. A 16% build time increase (as mentioned up-thread) is very significant for us.

@AaronBallman do you have any thoughts here?

I did see that #61811 mention "We should get performance data for that change and give feedback to WG21 if it looks like this is going to have a significant performance impact." So it sounds like this was somewhat anticipated?

In the standard, constraint satisfaction checking is done on the normalized form of a constraint.

Clang instead substitutes on the non-normalized form, which causes us to report substitution failures in template arguments or concept ids, which is non-conforming but unavoidable without a parameter mapping

I don't know much about concepts, but is there some way we could keep the old, fast, code path for most cases, and only use the new more expensive logic when that's not sufficient?

@AaronBallman
Copy link
Collaborator

I'm not sure how to proceed here. A 16% build time increase (as mentioned up-thread) is very significant for us.

@AaronBallman do you have any thoughts here?

16% is a bigger performance regression than I think we were anticipating.

I did see that #61811 mention "We should get performance data for that change and give feedback to WG21 if it looks like this is going to have a significant performance impact." So it sounds like this was somewhat anticipated?

I think we expected a performance hit, but more like 1-3%, not 10+%; that's significant enough that if we can't solve it, it should be feedback given to WG21 because that feels like too much of a regression to swallow. CC @cor3ntin (it may be a while before he responds, the dev conference is next week and WG21 meetings are the week after).

@cor3ntin
Copy link
Contributor Author

cor3ntin commented Oct 24, 2025

Note that I already pushed something that reduces the performance cost by a few percents. both me and Younan will keep exploring additional mitigations in the coming weeks.

We think there are specific expressions which are unexpectedly costly, we are still trying to isolate exactly the problematic cases.

@zmodem
Copy link
Collaborator

zmodem commented Oct 24, 2025

Thanks both! See you at the dev meeting :)

dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
…tion (llvm#164611)

When establishing constraint satisfaction, we were building expressions
even for compound constraint,

This is unnecessary extra work that accounts for ~20% of the performance
regression observed here
llvm#161671 (comment)
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
…tion (llvm#164611)

When establishing constraint satisfaction, we were building expressions
even for compound constraint,

This is unnecessary extra work that accounts for ~20% of the performance
regression observed here
llvm#161671 (comment)
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
The logical or expression should be parenthesized.
The issue was brought by llvm#161671

Fixes llvm#164104
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
…tion (llvm#164611)

When establishing constraint satisfaction, we were building expressions
even for compound constraint,

This is unnecessary extra work that accounts for ~20% of the performance
regression observed here
llvm#161671 (comment)
@alexfh
Copy link
Contributor

alexfh commented Nov 4, 2025

Hi @cor3ntin , we've started seeing Clang crashes after this commit. They only reproduce with our Clang header modules setup on a pretty large input. Reduction has been crawling slowly, so I don't expect to get a nice little test case soon (or ever). The crashes are sporadic, but reproduce more or less consistently when clang is built with msan:

==4090==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x558de04647e5 in clang::Sema::getNormalizedAssociatedConstraints(llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, llvm::ArrayRef<clang::AssociatedConstraint>) third_party/llvm/llvm-project/clang/lib/Sema/SemaConcept.cpp:2413:1
    #1 0x558de045b248 in CheckConstraintSatisfaction(clang::Sema&, clang::NamedDecl const*, llvm::ArrayRef<clang::AssociatedConstraint>, clang::MultiLevelTemplateArgumentList const&, clang::SourceRange, clang::ConstraintSatisfaction&, clang::Expr**, clang::ConceptReference const*) third_party/llvm/llvm-project/clang/lib/Sema/SemaConcept.cpp:1149:9
    #2 0x558de045aa66 in clang::Sema::CheckConstraintSatisfaction(llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, llvm::ArrayRef<clang::AssociatedConstraint>, clang::MultiLevelTemplateArgumentList const&, clang::SourceRange, clang::ConstraintSatisfaction&, clang::ConceptReference const*, clang::Expr**) third_party/llvm/llvm-project/clang/lib/Sema/SemaConcept.cpp:1221:7
    #3 0x558de046112e in CheckFunctionConstraintsWithoutInstantiation third_party/llvm/llvm-project/clang/lib/Sema/SemaConcept.cpp:1670:18
    #4 0x558de046112e in clang::Sema::CheckFunctionTemplateConstraints(clang::SourceLocation, clang::FunctionDecl*, llvm::ArrayRef<clang::TemplateArgument>, clang::ConstraintSatisfaction&) third_party/llvm/llvm-project/clang/lib/Sema/SemaConcept.cpp:1682:12
    #5 0x558de151791e in clang::Sema::FinishTemplateArgumentDeduction(clang::FunctionTemplateDecl*, llvm::SmallVectorImpl<clang::DeducedTemplateArgument>&, unsigned int, clang::FunctionDecl*&, clang::sema::TemplateDeductionInfo&, llvm::SmallVectorImpl<clang::Sema::OriginalCallArg> const*, bool, bool, bool, llvm::function_ref<bool (bool)>) third_party/llvm/llvm-project/clang/lib/Sema/SemaTemplateDeduction.cpp:3995:9
    #6 0x558de1600704 in operator() third_party/llvm/llvm-project/clang/lib/Sema/SemaTemplateDeduction.cpp:4736:14
    #7 0x558de1600704 in void llvm::function_ref<void ()>::callback_fn<clang::Sema::DeduceTemplateArguments(clang::FunctionTemplateDecl*, clang::TemplateArgumentListInfo*, llvm::ArrayRef<clang::Expr*>, clang::FunctionDecl*&, clang::sema::TemplateDeductionInfo&, bool, bool, bool, clang::QualType, clang::Expr::Classification, bool, llvm::function_ref<bool (llvm::ArrayRef<clang::QualType>, bool)>)::$_2>(long) third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:12
    #8 0x558de347d9cc in operator() third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:69:12
    #9 0x558de347d9cc in runWithSufficientStackSpace third_party/llvm/llvm-project/clang/include/clang/Basic/Stack.h:49:7
    #10 0x558de347d9cc in clang::StackExhaustionHandler::runWithSufficientStackSpace(clang::SourceLocation, llvm::function_ref<void ()>) third_party/llvm/llvm-project/clang/lib/Basic/StackExhaustionHandler.cpp:20:3
    #11 0x558de0154faf in clang::Sema::runWithSufficientStackSpace(clang::SourceLocation, llvm::function_ref<void ()>) third_party/llvm/llvm-project/clang/lib/Sema/Sema.cpp:629:16
    #12 0x558de1520980 in clang::Sema::DeduceTemplateArguments(clang::FunctionTemplateDecl*, clang::TemplateArgumentListInfo*, llvm::ArrayRef<clang::Expr*>, clang::FunctionDecl*&, clang::sema::TemplateDeductionInfo&, bool, bool, bool, clang::QualType, clang::Expr::Classification, bool, llvm::function_ref<bool (llvm::ArrayRef<clang::QualType>, bool)>) third_party/llvm/llvm-project/clang/lib/Sema/SemaTemplateDeduction.cpp:4735:3
    #13 0x558de11f5306 in AddTemplateOverloadCandidateImmediately(clang::Sema&, clang::OverloadCandidateSet&, clang::FunctionTemplateDecl*, clang::DeclAccessPair, clang::TemplateArgumentListInfo*, llvm::ArrayRef<clang::Expr*>, bool, bool, bool, clang::CallExpr::ADLCallKind, clang::OverloadCandidateParamOrder, bool) third_party/llvm/llvm-project/clang/lib/Sema/SemaOverload.cpp:8012:42
    #14 0x558de1217b63 in AddTemplateOverloadCandidate third_party/llvm/llvm-project/clang/lib/Sema/SemaOverload.cpp:11242:3
    #15 0x558de1217b63 in clang::OverloadCandidateSet::InjectNonDeducedTemplateCandidates(clang::Sema&) third_party/llvm/llvm-project/clang/lib/Sema/SemaOverload.cpp:11264:7
    #16 0x558de11e67f7 in clang::OverloadCandidateSet::BestViableFunction(clang::Sema&, clang::SourceLocation, clang::OverloadCandidate*&) third_party/llvm/llvm-project/clang/lib/Sema/SemaOverload.cpp:11360:3
    #17 0x558de0df66ec in clang::Sema::LookupSpecialMember(clang::CXXRecordDecl*, clang::CXXSpecialMemberKind, bool, bool, bool, bool, bool) third_party/llvm/llvm-project/clang/lib/Sema/SemaLookup.cpp:3578:15
    #18 0x558de089cceb in lookupCallFromSpecialMember(clang::Sema&, clang::CXXRecordDecl*, clang::CXXSpecialMemberKind, unsigned int, bool) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:7412:12
    #19 0x558de081e4ff in findTrivialSpecialMember third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10142:9
    #20 0x558de081e4ff in checkTrivialSubobjectCall(clang::Sema&, clang::SourceLocation, clang::QualType, bool, clang::CXXSpecialMemberKind, TrivialSubobjectKind, clang::TrivialABIHandling, bool) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10210:7
    #21 0x558de08214b1 in checkTrivialClassMembers(clang::Sema&, clang::CXXRecordDecl*, clang::CXXSpecialMemberKind, bool, clang::TrivialABIHandling, bool) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10292:10
    #22 0x558de08207fe in clang::Sema::SpecialMemberIsTrivial(clang::CXXMethodDecl*, clang::CXXSpecialMemberKind, clang::TrivialABIHandling, bool) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10419:8
    #23 0x558de0825dc3 in clang::Sema::DeclareImplicitMoveConstructor(clang::CXXRecordDecl*) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:16034:13
    #24 0x558de0822aef in clang::Sema::AddImplicitlyDeclaredMembersToClass(clang::CXXRecordDecl*) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10817:9
    #25 0x558de06945a2 in clang::Sema::ActOnFields(clang::Scope*, clang::SourceLocation, clang::Decl*, llvm::ArrayRef<clang::Decl*>, clang::SourceLocation, clang::SourceLocation, clang::ParsedAttributesView const&) third_party/llvm/llvm-project/clang/lib/Sema/SemaDecl.cpp:19889:7
    #26 0x558de082259b in clang::Sema::ActOnFinishCXXMemberSpecification(clang::Scope*, clang::SourceLocation, clang::Decl*, clang::SourceLocation, clang::SourceLocation, clang::ParsedAttributesView const&) third_party/llvm/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:10729:3
    #27 0x558ddfa83d11 in clang::Parser::ParseCXXMemberSpecification(clang::SourceLocation, clang::SourceLocation, clang::ParsedAttributes&, unsigned int, clang::Decl*) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:3768:13
    #28 0x558ddfa7b9e8 in clang::Parser::ParseClassSpecifier(clang::tok::TokenKind, clang::SourceLocation, clang::DeclSpec&, clang::Parser::ParsedTemplateInfo&, clang::AccessSpecifier, bool, clang::Parser::DeclSpecContext, clang::ParsedAttributes&) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:2174:7
    #29 0x558ddfadf814 in clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, clang::Parser::ParsedTemplateInfo&, clang::AccessSpecifier, clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*, clang::ImplicitTypenameContext) third_party/llvm/llvm-project/clang/lib/Parse/ParseDecl.cpp:4459:7
    #30 0x558ddfa8d77a in ParseDeclarationSpecifiers third_party/llvm/llvm-project/clang/include/clang/Parse/Parser.h:1842:12
    #31 0x558ddfa8d77a in clang::Parser::ParseCXXClassMemberDeclaration(clang::AccessSpecifier, clang::ParsedAttributes&, clang::Parser::ParsedTemplateInfo&, clang::ParsingDeclRAIIObject*) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:2864:3
    #32 0x558ddfa94bea in clang::Parser::ParseCXXClassMemberDeclarationWithPragmas(clang::AccessSpecifier&, clang::ParsedAttributes&, clang::TypeSpecifierType, clang::Decl*) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp
    #33 0x558ddfa839cb in clang::Parser::ParseCXXMemberSpecification(clang::SourceLocation, clang::SourceLocation, clang::ParsedAttributes&, unsigned int, clang::Decl*) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:3754:7
    #34 0x558ddfa7b9e8 in clang::Parser::ParseClassSpecifier(clang::tok::TokenKind, clang::SourceLocation, clang::DeclSpec&, clang::Parser::ParsedTemplateInfo&, clang::AccessSpecifier, bool, clang::Parser::DeclSpecContext, clang::ParsedAttributes&) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:2174:7
    #35 0x558ddfadf814 in clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, clang::Parser::ParsedTemplateInfo&, clang::AccessSpecifier, clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*, clang::ImplicitTypenameContext) third_party/llvm/llvm-project/clang/lib/Parse/ParseDecl.cpp:4459:7
    #36 0x558ddf992549 in ParseDeclarationSpecifiers third_party/llvm/llvm-project/clang/include/clang/Parse/Parser.h:1842:12
    #37 0x558ddf992549 in clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec&, clang::AccessSpecifier) third_party/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1091:3
    #38 0x558ddf991bb9 in clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*, clang::AccessSpecifier) third_party/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1209:12
    #39 0x558ddf98f281 in clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) third_party/llvm/llvm-project/clang/lib/Parse/Parser.cpp:1032:14
    #40 0x558ddfa63f04 in clang::Parser::ParseInnerNamespace(llvm::SmallVector<clang::Parser::InnerNamespaceInfo, 4u> const&, unsigned int, clang::SourceLocation&, clang::ParsedAttributes&, clang::BalancedDelimiterTracker&) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:240:7
    #41 0x558ddfa614c7 in clang::Parser::ParseNamespace(clang::DeclaratorContext, clang::SourceLocation&, clang::SourceLocation) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:218:3
    #42 0x558ddfad1334 in clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::ParsedAttributes&, clang::SourceLocation*) third_party/llvm/llvm-project/clang/lib/Parse/ParseDecl.cpp
    #43 0x558ddf98e4bd in clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) third_party/llvm/llvm-project/clang/lib/Parse/Parser.cpp
    #44 0x558ddfa63f04 in clang::Parser::ParseInnerNamespace(llvm::SmallVector<clang::Parser::InnerNamespaceInfo, 4u> const&, unsigned int, clang::SourceLocation&, clang::ParsedAttributes&, clang::BalancedDelimiterTracker&) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:240:7
    #45 0x558ddfa614c7 in clang::Parser::ParseNamespace(clang::DeclaratorContext, clang::SourceLocation&, clang::SourceLocation) third_party/llvm/llvm-project/clang/lib/Parse/ParseDeclCXX.cpp:218:3
    #46 0x558ddfad1334 in clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&, clang::ParsedAttributes&, clang::ParsedAttributes&, clang::SourceLocation*) third_party/llvm/llvm-project/clang/lib/Parse/ParseDecl.cpp
    #47 0x558ddf98e4bd in clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, clang::ParsedAttributes&, clang::ParsingDeclSpec*) third_party/llvm/llvm-project/clang/lib/Parse/Parser.cpp
    #48 0x558ddf989c0d in clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, clang::Sema::ModuleImportState&) third_party/llvm/llvm-project/clang/lib/Parse/Parser.cpp:745:12
    #49 0x558ddf96aeee in clang::ParseAST(clang::Sema&, bool, bool) third_party/llvm/llvm-project/clang/lib/Parse/ParseAST.cpp:170:20
    #50 0x558ddf2278c9 in clang::ASTFrontendAction::ExecuteAction() third_party/llvm/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1431:3
    #51 0x558ddd1246be in clang::CodeGenAction::ExecuteAction() third_party/llvm/llvm-project/clang/lib/CodeGen/CodeGenAction.cpp:1109:30
    #52 0x558ddf226532 in clang::FrontendAction::Execute() third_party/llvm/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1311:3
    #53 0x558ddf0acc76 in clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) third_party/llvm/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1008:33
    #54 0x558ddd1108bc in clang::ExecuteCompilerInvocation(clang::CompilerInstance*) third_party/llvm/llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:310:25
    #55 0x558ddd0e9923 in cc1_main(llvm::ArrayRef<char const*>, char const*, void*) third_party/llvm/llvm-project/clang/tools/driver/cc1_main.cpp:300:15
    #56 0x558ddd0dee70 in ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) third_party/llvm/llvm-project/clang/tools/driver/driver.cpp:225:12
    #57 0x558ddd0e60d3 in operator() third_party/llvm/llvm-project/clang/tools/driver/driver.cpp:369:12
    #58 0x558ddd0e60d3 in int llvm::function_ref<int (llvm::SmallVectorImpl<char const*>&)>::callback_fn<clang_main(int, char**, llvm::ToolContext const&)::$_0>(long, llvm::SmallVectorImpl<char const*>&) third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:12
    #59 0x558ddf5749e1 in operator() third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:69:12
    #60 0x558ddf5749e1 in operator() third_party/llvm/llvm-project/clang/lib/Driver/Job.cpp:437:34
    #61 0x558ddf5749e1 in void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::__msan::optional<llvm::StringRef>>, std::__msan::basic_string<char, std::__msan::char_traits<char>, std::__msan::allocator<char>>*, bool*) const::$_0>(long) third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:12
    #62 0x558deccf8397 in llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) () (
    #63 0x558ddf570ff9 in clang::driver::CC1Command::Execute(llvm::ArrayRef<std::__msan::optional<llvm::StringRef>>, std::__msan::basic_string<char, std::__msan::char_traits<char>, std::__msan::allocator<char>>*, bool*) const third_party/llvm/llvm-project/clang/lib/Driver/Job.cpp:437:12
    #64 0x558ddf4b9237 in clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const third_party/llvm/llvm-project/clang/lib/Driver/Compilation.cpp:196:15
    #65 0x558ddf4b980e in clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::__msan::pair<int, clang::driver::Command const*>>&, bool) const third_party/llvm/llvm-project/clang/lib/Driver/Compilation.cpp:246:19
    #66 0x558ddf503068 in clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::__msan::pair<int, clang::driver::Command const*>>&) third_party/llvm/llvm-project/clang/lib/Driver/Driver.cpp:2241:5
    #67 0x558ddd0dd2fa in clang_main(int, char**, llvm::ToolContext const&) third_party/llvm/llvm-project/clang/tools/driver/driver.cpp:407:21
    #68 0x558ddd0d8d6f in main llvm-project/clang/clang-driver.cpp:17:10
    #69 0x7f1225bb1351 in __libc_start_main ()
    #70 0x558ddd049fe9 in _start start.S:120

  Uninitialized value was created by a heap deallocation
    #0 0x558ddd0d8a89 in operator delete(void*, unsigned long, std::align_val_t) third_party/llvm/llvm-project/compiler-rt/lib/msan/msan_new_delete.cpp:108:3
    #1 0x558decd6f8b8 in llvm::deallocate_buffer(void*, unsigned long, unsigned long) () (BuildId: 95156bac43bc56e46756d69535047519)
    #2 0x558ddfeb30ac in deallocateBuckets third_party/llvm/llvm-project/llvm/include/llvm/ADT/DenseMap.h:834:5
    #3 0x558ddfeb30ac in ~DenseMap third_party/llvm/llvm-project/llvm/include/llvm/ADT/DenseMap.h:744:5
    #4 0x558ddfeb30ac in clang::ASTReader::ReadStmtFromStream(clang::serialization::ModuleFile&) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReaderStmt.cpp:4548:1
    #5 0x558ddfead686 in clang::ASTReader::ReadStmt(clang::serialization::ModuleFile&) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReaderStmt.cpp:2987:12
    #6 0x558ddfd8a838 in readStmt third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTRecordReader.h:123:37
    #7 0x558ddfd8a838 in readStmtRef third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTRecordReader.h:124:32
    #8 0x558ddfd8a838 in readExprRef llvm-project/clang/include/clang/AST/AbstractBasicReader.inc:933:40
    #9 0x558ddfd8a838 in clang::serialization::AbstractTypeReader<clang::ASTRecordReader>::readDecltypeType() llvm-project/clang/include/clang/AST/AbstractTypeReader.inc:325:45
    #10 0x558ddfcc9ce5 in clang::serialization::AbstractTypeReader<clang::ASTRecordReader>::read(clang::Type::TypeClass) llvm-project/clang/include/clang/AST/AbstractTypeReader.inc:50:14
    #11 0x558ddfcc9535 in clang::ASTReader::readTypeRecord(unsigned long) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReader.cpp:7197:21
    #12 0x558ddfcb8184 in clang::ASTReader::GetType(unsigned long) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReader.cpp:7931:26
    #13 0x558ddfd46ed8 in getLocalType third_party/llvm/llvm-project/clang/lib/Serialization/ASTReader.cpp:7945:10
    #14 0x558ddfd46ed8 in clang::ASTReader::readType(clang::serialization::ModuleFile&, llvm::SmallVector<unsigned long, 64u> const&, unsigned int&) third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTReader.h:2119:12
    #15 0x558ddfd8d76c in readType third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTRecordReader.h:175:20
    #16 0x558ddfd8d76c in readQualType third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTRecordReader.h:178:12
    #17 0x558ddfd8d76c in clang::serialization::AbstractTypeReader<clang::ASTRecordReader>::readFunctionProtoType() llvm-project/clang/include/clang/AST/AbstractTypeReader.inc:451:48
    #18 0x558ddfcc9cb9 in clang::serialization::AbstractTypeReader<clang::ASTRecordReader>::read(clang::Type::TypeClass) llvm-project/clang/include/clang/AST/AbstractTypeReader.inc:68:14
    #19 0x558ddfcc9535 in clang::ASTReader::readTypeRecord(unsigned long) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReader.cpp:7197:21
    #20 0x558ddfcb8184 in clang::ASTReader::GetType(unsigned long) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReader.cpp:7931:26
    #21 0x558ddfd46ed8 in getLocalType third_party/llvm/llvm-project/clang/lib/Serialization/ASTReader.cpp:7945:10
    #22 0x558ddfd46ed8 in clang::ASTReader::readType(clang::serialization::ModuleFile&, llvm::SmallVector<unsigned long, 64u> const&, unsigned int&) third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTReader.h:2119:12
    #23 0x558ddfdd731c in readType third_party/llvm/llvm-project/clang/include/clang/Serialization/ASTRecordReader.h:175:20
    #24 0x558ddfdd731c in clang::ASTDeclReader::VisitDeclaratorDecl(clang::DeclaratorDecl*) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp:911:29
    #25 0x558ddfdd90cb in clang::ASTDeclReader::VisitFunctionDecl(clang::FunctionDecl*) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp:1026:3
    #26 0x558ddfdcfdb7 in clang::declvisitor::Base<std::__msan::add_pointer, clang::ASTDeclReader, void>::Visit(clang::Decl*) llvm-project/clang/include/clang/AST/DeclNodes.inc:256:1
    #27 0x558ddfdcf435 in clang::ASTDeclReader::Visit(clang::Decl*) third_party/llvm/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp:527:37
    #28 0x558ddfe5e5ca in operator() third_party/llvm/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp:4249:53
    #29 0x558ddfe5e5ca in void llvm::function_ref<void ()>::callback_fn<clang::ASTReader::ReadDeclRecord(clang::GlobalDeclID)::$_1>(long) third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:12
    #30 0x558de347d9cc in operator() third_party/llvm/llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:69:12
    #31 0x558de347d9cc in runWithSufficientStackSpace third_party/llvm/llvm-project/clang/include/clang/Basic/Stack.h:49:7
    #32 0x558de347d9cc in clang::StackExhaustionHandler::runWithSufficientStackSpace(clang::SourceLocation, llvm::function_ref<void ()>) third_party/llvm/llvm-project/clang/lib/Basic/StackExhaustionHandler.cpp:20:3

SUMMARY: MemorySanitizer: use-of-uninitialized-value third_party/llvm/llvm-project/clang/lib/Sema/SemaConcept.cpp:2413:1 in clang::Sema::getNormalizedAssociatedConstraints(llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, llvm::ArrayRef<clang::AssociatedConstraint>) (//third_party/llvm/llvm-project/clang:clang)

It looks like serialization or deserialization issue.

@AaronBallman
Copy link
Collaborator

Hi @cor3ntin , we've started seeing Clang crashes after this commit.

FYI but @cor3ntin is out at WG21 meetings this week, so it may be a bit before he responds.

@alexfh
Copy link
Contributor

alexfh commented Nov 6, 2025

Hi @cor3ntin , we've started seeing Clang crashes after this commit.

FYI but @cor3ntin is out at WG21 meetings this week, so it may be a bit before he responds.

I see. We'll try to dig a bit deeper ourselves, maybe we'll get somewhere before @cor3ntin is back. And the test case reduction is running in the background (it's 30% through now, hopefully, there will be more progress by the end of the week).

@alexfh
Copy link
Contributor

alexfh commented Nov 12, 2025

After a few iterations of cvise and manual reduction I came up with this:

//--- test.sh
#!/bin/bash
$CLANG -isystem . -fmodule-name=stl -fmodule-map-file=stl.cppmap -Xclang=-fno-cxx-modules -Xclang=-fmodule-map-file-home-is-cwd -xc++ -Xclang=-emit-module -Xclang=-fmodules-local-submodule-visibility -fmodules -fno-implicit-modules -fno-implicit-module-maps -std=gnu++20 -nostdinc++ -nostdlib++ -c stl.cppmap -o stl.pcm && \
  $CLANG -isystem . -fmodule-name=test -Xclang=-fno-cxx-modules -Xclang=-fmodule-map-file-home-is-cwd -fmodules -fno-implicit-modules -fno-implicit-module-maps -Xclang=-fmodule-file=stl.pcm -fmodule-map-file=stl.cppmap -std=gnu++20 -nostdinc++ -nostdlib++ -fsyntax-only test.cc
//--- test.cc
#include <bitset>
using std::size_t;
namespace std {
template <> struct char_traits<char> {
  using comparison_category = strong_ordering;
};
template <class _CharT, class> class basic_string_view {
public:
  using size_type = size_t;
  basic_string_view(_CharT *, size_type);
  template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
  basic_string_view(_It, _End);
  int compare(basic_string_view);
};
template <class _CharT, class _Traits>
auto operator>(basic_string_view<_CharT, _Traits> __lhs,
               type_identity_t<basic_string_view<_CharT>> __rhs) {
  (__comparison_category<typename _Traits::comparison_category>);
  return (__lhs.compare(__rhs));
}
template <class...> class tuple {};
template <class... _Tp> tuple<_Tp...> tie(_Tp...);
template <class... _Tp, class... _Up>
  requires true
common_comparison_category_t<__synth_three_way_result<_Tp>...>
operator<=>(tuple<_Tp...>, tuple<_Up...>);
template <class _ToType, class _FromType>
  requires true
_ToType bit_cast(_FromType);
template <class _Tp>
concept __is_derived_from_optional = requires(_Tp __t) { [] {}(__t); };
template <class> class optional {};
template <class _Tp, class _Up>
  requires(!__is_derived_from_optional<_Up>)
_Up operator<=(_Tp, _Up);
template <class _CharT, class, class> class basic_string {
public:
  using __self_view = basic_string_view<_CharT>;
  operator __self_view() {}
};
template <class _CharT, class _Traits, class _Allocator>
auto operator<=>(basic_string<_CharT> __lhs,
                 basic_string<_Traits, _Allocator> __rhs) {
  return basic_string_view<_CharT>(__lhs) > __rhs;
}
template <class> struct atomic {};
template <class _Tp>
  requires is_floating_point_v<_Tp>
struct atomic<_Tp>;
template <class _InputIterator, class _Size, class _OutputIterator>
constexpr _OutputIterator copy_n(_InputIterator __first, _Size,
                                 _OutputIterator __result) {
  return copy(__first, __first, __result);
}
template <class _JoinViewIterator>
  requires true
struct __segmented_iterator_traits<_JoinViewIterator>;
template <class _Tp, size_t _Size> struct array {
  using value_type = _Tp;
  _Tp __elems_[_Size];
  constexpr value_type *data() { return __elems_; }
};
template <class _Fn>
  requires true
auto bind_front(_Fn) {}
enum class _Trait { _TriviallyAvailable, _Unavailable };
template <typename _Tp, template <typename> class _IsTriviallyAvailable,
          template <typename> class>
constexpr _Trait __trait =
    _IsTriviallyAvailable<_Tp>::value ? _Trait::_TriviallyAvailable
                                      : _Trait::_Unavailable;
constexpr _Trait __common_trait(initializer_list<_Trait>) {
  _Trait __result = _Trait::_TriviallyAvailable;
  return __result;
}
template <typename... _Types> struct __traits {
  static constexpr _Trait __copy_constructible_trait =
      __common_trait({__trait<_Types, is_trivially_copy_constructible,
                              is_copy_constructible>...});
};
template <class _Traits, _Trait = _Traits::__copy_constructible_trait>
class __copy_constructor {};
template <class... _Types> class variant {
  __copy_constructor<__traits<_Types...>> __impl_;
};
} // namespace std
namespace absl {
template <typename T> using remove_cvref_t = std::remove_cvref<T>;
template <typename> class Span {};
template <typename T> Span<T> MakeSpan(T *);
template <class Hash> class raw_hash_set {
  using e = remove_cvref_t<decltype(std::declval<Hash>()(std::declval<int>))>;
  std::atomic<char> p(char *ptr) {
    std::string_view(ptr, 0);
    {
      std::bit_cast<void *>(ptr);
    }
  };
};
template <typename F>
F WrapUnique(F)
  requires true;
} // namespace absl
class MD {
public:
  static bool Equals();
};
namespace util {
template <class> struct tag;
template <class> struct intrinsics;
template <class, class = void> struct has_all_el {};
template <class T> struct has_all_el<T, typename tag<T>::e>;
template <class T> struct has_all_elements : has_all_el<T> {};
template <size_t> struct wrap {};
template <size_t N> using rank = wrap<N>;
rank<0> rank_selector;
namespace internal {
template <typename... C> class ChainComparators {
  ChainComparators()
    requires true;
};
} // namespace internal
template <typename... C>
internal::ChainComparators<C...> ChainComparators(C...);
class {
  bool oeto() { ChainComparators(); }
} D;
class I6 {
  bool p(I6 rhs) { ChainComparators(rhs); }
};
template <size_t storage_size> class CompileTimeString {
public:
  template <size_t length>
  consteval CompileTimeString(const char (&s)[length]) : s(AsStdArray(s)) {}
  std::array<char, storage_size> s;
  template <size_t length>
  consteval std::array<char, storage_size> AsStdArray(const char (&s)[length]) {
    std::array<char, storage_size> out;
    std::copy_n(s, storage_size, out.data());
    return out;
  }
};
template <size_t length>
CompileTimeString(const char (&)[length]) -> CompileTimeString<length - 1>;
template <class T>
  requires true
struct tag<T>;
template <class = void> struct hasher {
  template <class T> size_t b(T, rank<0>);
  template <class T, class = std::enable_if<has_all_elements<T>::a>>
  size_t b(T, rank<4>);
  template <class T, class Self = hasher,
            class = decltype(Self().b(std::declval<T>, rank_selector))>
  size_t operator()(T);
};
using hash_t = hasher<>;
struct TaskId {
  bool operator<(TaskId other) { tie(t, l) < tie(t); }
  std::string t;
  uint16_t l;
};
template <auto P>
  requires true
class Opt {
  Opt<MD::Equals>;
};
CompileTimeString s = "";
} // namespace util
class C {
  void g() { std::bind_front(this); }
};
template <size_t> class PT {
  template <size_t k>
    requires true
  PT(PT<k>);
};
void q() { absl::WrapUnique(new int); }
template <typename T>
  requires true
void Su(T) {
  Su(std::string());
}
class Packet {
public:
  template <typename T>
    requires true
  T *Get();
  absl::raw_hash_set<util::hash_t> ap_;
};
template <typename H>
  requires true
H Construct;
template <typename H>
  requires true
void Enc() {
  Construct<int>;
  Enc<int>;
  std::variant<PT<16>, PT<32>> y_;
}
uint8_t Gset(std::optional<size_t> n) { (n <= 0); }
struct POption {
  void Parse(Packet *p) {
    Parse2<int>(
        absl::MakeSpan(reinterpret_cast<const char *>(p->Get<POption>())));
  }
  template <typename AddonT>
    requires true
  bool Parse2(absl::Span<const char>);
};
enum AE { AT };
class A {
public:
  static constexpr AE ST = AT;
};
class S2 {
  S2(S2 &);
};
template <auto eid>
  requires true
class B;
template <typename T>
using CanonicalType =
    std::conditional<std::convertible_to<T, std::string_view>, std::string, T>;
template <typename> class M;
template <typename Anchor, typename... Fields>
concept IsValidAnchor = std::derived_from<Anchor, M<CanonicalType<Fields>...>>;
template <auto eid>
  requires true
class P {
  using Bas = B<eid>;
  template <typename Anchor>
    requires true
  P(Anchor);
  template <typename Anchor>
    requires IsValidAnchor<Anchor, std::string>
  P(Anchor);
  S2 s;
};
struct S {
  P<A::ST> p;
};
//--- bitset
#include <equality_comparable.h>
#include <synth_three_way.h>
namespace std {
template <class _Lhs, class>
concept assignable_from = requires(_Lhs __lhs) {
  { __lhs } -> same_as<_Lhs>;
};
template <class _Tp> using __add_lvalue_reference_t = _Tp;
template <class> struct is_copy_constructible;
template <class _Tp> constexpr bool is_class_v = __is_class(_Tp);
template <class _Tp>
concept __class_or_enum = is_class_v<_Tp>;
namespace ranges {
namespace __swap {
template <class _Tp, class>
concept __unqualified_swappable_with = requires(_Tp __t) { swap(__t); };
template <class _Tp>
concept __exchangeable =
    !__unqualified_swappable_with<_Tp, _Tp> && assignable_from<_Tp &, _Tp>;
struct __fn {
  template <class _Tp, class _Up>
    requires __unqualified_swappable_with<_Tp, _Up>
  void operator()(_Tp, _Up);
  template <__exchangeable _Tp> void operator()(_Tp, _Tp);
};
} // namespace __swap
namespace {
auto swap = __swap::__fn{};
}
} // namespace ranges
template <class _Tp>
concept swappable = requires(_Tp __a, _Tp __b) { ranges::swap(__a, __b); };
template <class _Tp>
concept movable = swappable<_Tp>;
template <class _Tp> using remove_cv_t = _Tp;
template <class> struct __libcpp_is_floating_point : false_type {};
template <class _Tp>
struct is_floating_point : __libcpp_is_floating_point<_Tp> {};
template <class _Tp>
constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
template <bool, class, class> struct conditional;
template <bool> struct enable_if;
template <bool _Bp> using __enable_if_t = enable_if<_Bp>;
template <class _Tp>
concept __dereferenceable = requires(_Tp __t) { __t; };
template <__dereferenceable>
using iter_reference_t = struct random_access_iterator_tag;
} // namespace std
typedef char __uint8_t;
typedef int __uint16_t;
typedef __uint8_t uint8_t;
typedef __uint16_t uint16_t;
namespace std {
template <class _T1, class _T2> struct pair {
  _T1 first;
  _T2 second;
};
template <class _T1, class _T2> constexpr pair<_T1, _T2> make_pair(_T1, _T2) {
  return pair<_T1, _T2>();
}
template <class _Iter, class> struct __unwrap_range_impl {
  static constexpr auto __unwrap(_Iter __first, _Iter __last) {
    return pair{__first, __last};
  }
};
template <class _Iter, class _Sent>
constexpr auto __unwrap_range(_Iter __first, _Sent __last) {
  return __unwrap_range_impl<_Iter, _Sent>::__unwrap(__first, __last);
}
template <class _In, class _Out>
constexpr pair<_In *, _Out *> __copy_trivial_impl(_In *, _In *__last,
                                                  _Out *__result) {
  return make_pair(__last, __result);
}
template <class _Algorithm, class _InIter, class _Sent, class _OutIter>
constexpr pair<_InIter, _OutIter>
__copy_move_unwrap_iters(_InIter __first, _Sent __last, _OutIter __out_first) {
  auto __range = __unwrap_range(__first, __last);
  auto __result = _Algorithm()(__first, (__range.second), __out_first);
  return make_pair(__first, ((__result.second)));
}
template <class _Ep> class initializer_list {
  const _Ep *_;
  size_t e;
};
template <class> struct __segmented_iterator_traits;
template <class, size_t = 0> bool __has_specialization_v;
template <class _Tp> bool __has_specialization_v<_Tp, sizeof(_Tp)>;
template <class _Iterator>
const bool __is_segmented_iterator_v =
    __has_specialization_v<__segmented_iterator_traits<_Iterator>>;
struct __copy_impl {
  template <class _InIter, class _OutIter,
            __enable_if_t<__is_segmented_iterator_v<_InIter>> = 0>
  pair<_InIter, _OutIter> operator()(_InIter, _InIter, _OutIter);
  template <class _In, class _Out>
  constexpr pair<_In *, _Out *> operator()(_In *__first, _In *__last,
                                           _Out *__result) {
    return __copy_trivial_impl(__first, __last, __result);
  }
};
template <class _InIter, class _Sent, class _OutIter>
pair<_InIter, _OutIter> constexpr __copy(_InIter __first, _Sent __last,
                                         _OutIter __result) {
  return __copy_move_unwrap_iters<__copy_impl>(__first, __last, __result);
}
template <class _InputIterator, class _OutputIterator>
constexpr _OutputIterator copy(_InputIterator __first, _InputIterator __last,
                               _OutputIterator __result) {
  return __copy(__first, __last, __result).second;
}
template <class _Bp, class _Dp>
inline constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp);
template <class, class _Bp>
concept derived_from = is_base_of_v<_Bp, _Bp>;
namespace ranges {
namespace __iter_move {
template <class _Tp>
concept __unqualified_iter_move = __class_or_enum<remove_cv_t<_Tp>>;
template <class _Tp>
concept __move_deref = requires(_Tp &__t) { __t; };
template <class _Tp>
concept __just_deref = !__unqualified_iter_move<_Tp> && !__move_deref<_Tp>;
struct __fn {
  template <class _Ip>
    requires __unqualified_iter_move<_Ip>
  auto operator()(_Ip);
  template <class _Ip>
    requires __move_deref<_Ip>
  constexpr auto operator()(_Ip __i) -> decltype(__i);
  template <class _Ip>
    requires __just_deref<_Ip>
  auto operator()(_Ip);
};
} // namespace __iter_move
namespace {
auto iter_move = __iter_move::__fn{};
}
} // namespace ranges
template <__dereferenceable _Tp>
using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<_Tp>));
template <class _In>
concept __indirectly_readable_impl =
    common_reference_with<iter_reference_t<_In>, iter_rvalue_reference_t<_In>>;
template <class _In>
concept indirectly_readable = __indirectly_readable_impl<remove_cvref_t<_In>>;
template <class _Ip>
concept weakly_incrementable = movable<_Ip>;
template <class _Ip>
concept input_or_output_iterator = requires(_Ip __i) {
  { __i } -> __referenceable;
} && weakly_incrementable<_Ip>;
template <class _Sp, class _Ip>
concept sentinel_for = __weakly_equality_comparable_with<_Sp, _Ip>;
template <class, class _Ip>
concept sized_sentinel_for = requires(_Ip __i) { __i; };
template <class _Ip>
concept input_iterator =
    input_or_output_iterator<_Ip> && indirectly_readable<_Ip>;
template <class _Ip>
concept forward_iterator = input_iterator<_Ip> && sentinel_for<_Ip, _Ip>;
template <class _Ip>
concept bidirectional_iterator = forward_iterator<_Ip>;
template <class _Ip>
concept random_access_iterator = bidirectional_iterator<_Ip>;
template <class _Ip>
concept contiguous_iterator = random_access_iterator<_Ip>;
template <class _Tp>
struct is_trivially_copy_constructible
    : integral_constant<bool, __is_trivially_constructible(
                                  _Tp, __add_lvalue_reference_t<const _Tp>)> {};
template <class> struct char_traits;
template <class _CharT, class = _CharT, class = _CharT> class basic_string;
using string = basic_string<char>;
template <class _CharT, class = char_traits<_CharT>> class basic_string_view;
typedef basic_string_view<char> string_view;
} // namespace std
//--- synth_three_way.h
#ifndef _LIBCPP___COMPARE_SYNTH_THREE_WAY_H
#define _LIBCPP___COMPARE_SYNTH_THREE_WAY_H
#include <equality_comparable.h>
namespace std {
struct _CmpUnspecifiedParam {
  template <class _Tp> _CmpUnspecifiedParam(_Tp);
};
class partial_ordering;
class weak_ordering {
public:
  static weak_ordering equivalent;
  friend bool operator<(weak_ordering, _CmpUnspecifiedParam);
};
class strong_ordering;
template <class _Tp>
concept __comparison_category = is_same_v<_Tp, strong_ordering>;
using size_t = decltype(sizeof(int));
namespace __comp_detail {
auto __get_comp_type() { return weak_ordering::equivalent; }
} // namespace __comp_detail
template <class...> struct common_comparison_category {
  using type = decltype(__comp_detail::__get_comp_type());
};
template <class...>
using common_comparison_category_t = common_comparison_category<>::type;
template <class _Tp, class>
concept __partially_ordered_with = requires(_Tp __t) {
  { __t } -> __boolean_testable;
};
template <class, class _Cat>
concept __compares_as = same_as<common_comparison_category_t<>, _Cat>;
template <class _Tp, class _Up, class _Cat = partial_ordering>
concept three_way_comparable_with =
    __weakly_equality_comparable_with<_Tp, _Up> &&
    __partially_ordered_with<_Tp, _Up> && requires(_Up __u) {
      { __u } -> __compares_as<_Cat>;
    };
auto __synth_three_way = []<class _Tp, class _Up>(_Tp __t, _Up __u)
  requires requires {
    { __t < __u };
  }
{
  if (three_way_comparable_with<_Tp, _Up>) {
  }
};
template <class _Tp, class _Up = _Tp>
using __synth_three_way_result = decltype(__synth_three_way(_Tp(), _Up()));
} // namespace std
#endif
//--- equality_comparable.h
namespace std {
template <class _Tp, _Tp __v> struct integral_constant {
  static const _Tp value = __v;
};
typedef integral_constant<bool, false> false_type;
template <bool _Val> using _BoolConstant = integral_constant<bool, _Val>;
template <class _Tp, class _Up> constexpr bool is_same_v = __is_same(_Tp, _Up);
template <class _Tp, class _Up>
using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
template <class _From, class _To>
constexpr bool is_convertible_v = __is_convertible(_From, _To);
template <class _Tp> _Tp declval();
template <class _From, class _To>
concept convertible_to = is_convertible_v<_From, _To>;
template <class _Tp>
concept __boolean_testable_impl = convertible_to<_Tp, bool>;
template <class _Tp>
concept __boolean_testable = requires(_Tp __t) {
  { __t } -> __boolean_testable_impl;
};
template <class _Tp, class _Up>
concept __same_as_impl = _IsSame<_Tp, _Up>::value;
template <class _Tp, class _Up>
concept same_as = __same_as_impl<_Up, _Tp>;
template <class, class = void> bool __is_referenceable_v;
template <class _Tp> const bool __is_referenceable_v<_Tp> = true;
template <class _Tp>
concept __referenceable = __is_referenceable_v<_Tp>;
template <class _Tp> using add_pointer_t = _Tp;
template <class _Tp> struct type_identity {
  typedef _Tp type;
};
template <class _Tp> using type_identity_t = type_identity<_Tp>::type;
template <class _From, class> using __copy_cv_t = _From;
template <class> bool is_reference_v;
template <class> struct remove_cvref;
template <class _Tp> using remove_cvref_t = _Tp;
template <class _Tp> using remove_reference_t = _Tp;
template <class, class _Yp> using __cond_res = decltype(false ?: declval<_Yp>);
template <class _Ap, class _Bp, class = _Ap, class = remove_reference_t<_Bp>>
struct __common_ref;
template <class _Xp, class _Yp> using __common_ref_t = __common_ref<_Xp, _Yp>;
template <class _Xp, class _Yp>
using __cv_cond_res = __cond_res<__copy_cv_t<_Xp, _Yp>, __copy_cv_t<_Yp, _Xp>>;
template <class _Ap, class _Bp, class _Xp, class _Yp>
  requires is_reference_v<__cv_cond_res<_Xp, _Yp>>
struct __common_ref<_Ap, _Bp, _Xp, _Yp>;
template <class _Tp, class _Up> using __common_ref_D = __common_ref_t<_Tp, _Up>;
template <class _Ap, class _Bp, class _Xp, class _Yp>
  requires is_convertible_v<_Ap, __common_ref_D<_Xp, _Yp>>
struct __common_ref<_Ap, _Bp, _Xp, _Yp>;
template <class _Tp, class _Up>
  requires is_convertible_v<_Up, add_pointer_t<__common_ref_t<_Tp, _Up>>>
_Up common_reference_with;
template <class _Tp, class>
concept __weakly_equality_comparable_with = requires(_Tp __t) {
  { __t } -> __boolean_testable;
};
} // namespace std
//--- stl.cppmap
module "stl" {
module "synth_three_way.h" {
header "synth_three_way.h"
}
header "bitset"
}

(as usual, this may easily be overreduced and not completely valid, but the initial inputs were totally fine, AFAICT)

@alexfh
Copy link
Contributor

alexfh commented Nov 12, 2025

After a few iterations of cvise and manual reduction I came up with this:

@cor3ntin please take a look.

@cor3ntin
Copy link
Contributor Author

I am still afaik, I will take a look when I come back - hopefully next week

Cc @zyn0217

@alexfh
Copy link
Contributor

alexfh commented Nov 12, 2025

I am still afaik, I will take a look when I come back - hopefully next week

Thanks! This is not a pressing issue for us now, since we could mitigate this for a time being. Have a nice time off!

@alexfh
Copy link
Contributor

alexfh commented Nov 13, 2025

It looks like the problem is the same as #165238, and it was fixed by #165352.

@zmodem
Copy link
Collaborator

zmodem commented Nov 14, 2025

Coming back to the compile-time issue, I've been trying to find examples that may be instructive in figuring out what's getting slower.

The attached file seems interesting, because it's basically a large table, and so it uses a few constructs many many times:usb_ids_gen.ii.gz

Building with

clang -cc1 -triple x86_64-unknown-linux-gnu -O0 -emit-obj -disable-llvm-verifier -discard-value-names -main-file-name usb_ids_gen.cc -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fmerge-all-constants -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse3 -tune-cpu generic -debug-info-kind=constructor -dwarf-version=4 -debugger-tuning=gdb -ggnu-pubnames -gsimple-template-names=simple -std=c++20 -fdeprecated-macro -ferror-limit 19 -fmessage-length=179 -fvisibility=hidden -fvisibility-inlines-hidden -fwrapv -fwrapv-pointer -pthread -stack-protector 1 -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -Qn -fcolor-diagnostics -fuse-ctor-homing -fcomplete-member-pointers /tmp/usb_ids_gen.ii -o /dev/null

is 140% slower after this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clang considers fold expanded constraint ambiguous when it shouldn't be Clang type substitution for concepts is too eager