[llvm-branch-commits] [clang] release/23.x: [NFC][clang][Serialization] Fix std::set_difference sorting mismatch in ASTReader (#219053) (PR #219097)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Aug 26 20:23:11 PDT 2026


https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/219097

Backport dc222c2de55988f5359262a0e29fed5c14e824e7

Requested by: @ChuanqiXu9

>From 8ff757c089a6af50a4c600801be7b79d1954b3d8 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Wed, 26 Aug 2026 23:10:57 -0400
Subject: [PATCH] [NFC][clang][Serialization] Fix std::set_difference sorting
 mismatch in ASTReader (#219053)

Fixes a `std::set_difference` sorting violation in
`ASTReader::checkTargetOptions` that causes a crash when building clang
with `LLVM_ENABLE_EXPENSIVE_CHECKS` on libstdc++.

`accumulateFeaturesAsWritten` sorts target features using a custom
comparator that strips the `+`/`-` prefix (i.e. comparing `A.substr(1) <
B.substr(1)`). However, `std::set_difference` was being called with the
default `std::string::operator<` comparator, which does not match the
sorting order because `+` (ASCII 0x2B) is less than `-` (ASCII 0x2D).
For example, `["-cx16", "+sse2"]` is correctly sorted according to the
custom comparator, but incorrectly sorted according to the default
lexicographical comparator.

This patch fixes the issue by passing the same custom comparator used
for sorting to both `std::set_difference` calls.

Fixes #219046.

(cherry picked from commit dc222c2de55988f5359262a0e29fed5c14e824e7)
---
 clang/lib/Serialization/ASTReader.cpp        | 13 ++++++++----
 clang/test/Modules/merge-target-features.cpp | 22 ++++++++++++++++++++
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 4d3816d686730..1a437f3ebab98 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -523,13 +523,18 @@ static bool checkTargetOptions(const TargetOptions &TargetOpts,
 
   // We compute the set difference in both directions explicitly so that we can
   // diagnose the differences differently.
+  auto FeatureLess = [](StringRef A, StringRef B) {
+    return A.substr(1) < B.substr(1);
+  };
+
   SmallVector<StringRef, 4> UnmatchedExistingFeatures, UnmatchedReadFeatures;
-  std::set_difference(
-      ExistingFeatures.begin(), ExistingFeatures.end(), ReadFeatures.begin(),
-      ReadFeatures.end(), std::back_inserter(UnmatchedExistingFeatures));
+  std::set_difference(ExistingFeatures.begin(), ExistingFeatures.end(),
+                      ReadFeatures.begin(), ReadFeatures.end(),
+                      std::back_inserter(UnmatchedExistingFeatures),
+                      FeatureLess);
   std::set_difference(ReadFeatures.begin(), ReadFeatures.end(),
                       ExistingFeatures.begin(), ExistingFeatures.end(),
-                      std::back_inserter(UnmatchedReadFeatures));
+                      std::back_inserter(UnmatchedReadFeatures), FeatureLess);
 
   // If we are allowing compatible differences and the read feature set is
   // a strict subset of the existing feature set, there is nothing to diagnose.
diff --git a/clang/test/Modules/merge-target-features.cpp b/clang/test/Modules/merge-target-features.cpp
index c3678cbea11cb..f008492b7e341 100644
--- a/clang/test/Modules/merge-target-features.cpp
+++ b/clang/test/Modules/merge-target-features.cpp
@@ -148,6 +148,28 @@
 // RUN:   -fsyntax-only merge-target-features.cpp 2>&1 \
 // RUN:   | FileCheck --allow-empty --check-prefix=IGNORED2 %s
 // IGNORED2-NOT: error:
+//
+// RUN: %clang_cc1 -fmodules -x c++ -fmodules-cache-path=%t \
+// RUN:   -iquote Inputs/merge-target-features \
+// RUN:   -fno-implicit-modules \
+// RUN:   -fmodule-map-file-home-is-cwd \
+// RUN:   -emit-module -fmodule-name=foo -o %t/foo-order.pcm \
+// RUN:   -triple i386-unknown-unknown \
+// RUN:   -target-cpu i386 -target-feature -cx16 -target-feature +sse2 \
+// RUN:   Inputs/merge-target-features/module.modulemap
+//
+// RUN: not %clang_cc1 -fmodules -x c++ -fmodules-cache-path=%t \
+// RUN:   -iquote Inputs/merge-target-features \
+// RUN:   -fno-implicit-modules \
+// RUN:   -fmodule-map-file-home-is-cwd \
+// RUN:   -fmodule-map-file=Inputs/merge-target-features/module.modulemap \
+// RUN:   -fmodule-file=%t/foo-order.pcm \
+// RUN:   -triple i386-unknown-unknown \
+// RUN:   -target-cpu i386 -target-feature +sse2 \
+// RUN:   -fsyntax-only merge-target-features.cpp 2>&1 \
+// RUN:   | FileCheck --check-prefix=ORDER --implicit-check-not=error: %s
+// ORDER: error: precompiled file '{{.*}}foo-order.pcm' was compiled with the target feature '-cx16' but the current translation unit is not
+// ORDER: error: {{.*}} configuration mismatch
 
 #include "foo.h"
 



More information about the llvm-branch-commits mailing list