Skip to content

[clang] Crash in SemaConcept.cpp / Sema::getNormalizedAssociatedConstraints (invalidated iterator?) #165238

@jiixyj

Description

@jiixyj

On 1322e71 I'm getting a crash in SemaConcept.cpp when compiling some C++ code (this is a RelWithDebInfo build with assertions enabled):

 #7 0x00007ff333c3eefc abort ./stdlib/abort.c:81:3                                                                                                                                              
 #8 0x00007ff333c3ee6a __assert_perror_fail ./assert/assert-perr.c:31:1                                                                                                                         
 #9 0x000056107c5555ee llvm::DenseMapIterator<llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, clang::NormalizedConstraint*, llvm::DenseMapInfo<llvm::Poi
nterUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, void>, llvm::detail::DenseMapPair<llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement 
const*>, clang::NormalizedConstraint*>, false>::operator*() const /freebsd/data/linux/git-net/llvm-project/llvm/include/llvm/ADT/DenseMap.h:1217:5                                              
#10 0x000056107c5555ee llvm::DenseMapIterator<llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, clang::NormalizedConstraint*, llvm::DenseMapInfo<llvm::Poi
nterUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, void>, llvm::detail::DenseMapPair<llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement 
const*>, clang::NormalizedConstraint*>, false>::operator->() const /freebsd/data/linux/git-net/llvm-project/llvm/include/llvm/ADT/DenseMap.h:1220:54                                            
#11 0x000056107c5555ee clang::Sema::getNormalizedAssociatedConstraints(llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, llvm::ArrayRef<clang::AssociatedC
onstraint>) /freebsd/data/linux/git-net/llvm-project/clang/lib/Sema/SemaConcept.cpp:2419:10                                                                                                     
#12 0x000056107c551812 CheckConstraintSatisfaction(clang::Sema&, clang::NamedDecl const*, llvm::ArrayRef<clang::AssociatedConstraint>, clang::MultiLevelTemplateArgumentList const&, clang::Sour
ceRange, clang::ConstraintSatisfaction&, clang::Expr**, clang::ConceptReference const*) /freebsd/data/linux/git-net/llvm-project/clang/lib/Sema/SemaConcept.cpp:1155:8                          
#13 0x000056107c551582 clang::Sema::CheckConstraintSatisfaction(llvm::PointerUnion<clang::NamedDecl const*, clang::concepts::NestedRequirement const*>, llvm::ArrayRef<clang::AssociatedConstrai
nt>, clang::MultiLevelTemplateArgumentList const&, clang::SourceRange, clang::ConstraintSatisfaction&, clang::ConceptReference const*, clang::Expr**) /freebsd/data/linux/git-net/llvm-project/c
lang/lib/Sema/SemaConcept.cpp:1227:7                                                                              

This comes from the line return CacheEntry->second;. It looks like this iterator gets invalidated, maybe by the earlier call SubstituteParameterMappings(*this).substitute(*Normalized).

This works around the issue:

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f04cc454cdb7..8135e1bc239f 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -2408,12 +2408,16 @@ const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
   if (CacheEntry == NormalizationCache.end()) {
     auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
         *this, ND, AssociatedConstraints);
-    CacheEntry =
-        NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
-            .first;
+    auto [it, inserted] = NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized);
+    assert(inserted);
+    assert(it != NormalizationCache.end());
+
     if (!Normalized ||
         SubstituteParameterMappings(*this).substitute(*Normalized))
       return nullptr;
+
+    CacheEntry = NormalizationCache.find(ConstrainedDeclOrNestedReq);
+    assert(CacheEntry != NormalizationCache.end());
   }
   return CacheEntry->second;
 }

Would a minimal reproducer help? It's a bit difficult, because I'm using C++20 modules...

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"conceptsC++20 conceptscrashPrefer [crash-on-valid] or [crash-on-invalid]

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions