Skip to content

[clang] deduplicate target-features for modules#187614

Merged
fmayer merged 1 commit into
mainfrom
users/fmayer/spr/clang-deduplicate-target-features-for-modules
Apr 8, 2026
Merged

[clang] deduplicate target-features for modules#187614
fmayer merged 1 commit into
mainfrom
users/fmayer/spr/clang-deduplicate-target-features-for-modules

Conversation

@fmayer

@fmayer fmayer commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Previously, double passing a target feature would make the module
incompatible with a compilation unit that only passes it once.

The motivating problem is, when we pass -target-features +tagged-globals
as well as -fsanitize=hwaddress, which adds a second copy, the module
is incompatible with one built with only one -target-features +tagged-globals.

Created using spr 1.3.7
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:modules C++20 modules and Clang Header Modules labels Mar 20, 2026
@llvmbot

llvmbot commented Mar 20, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Florian Mayer (fmayer)

Changes

Previously, double passing a target feature would make the module
incompatible with a compilation unit that only passes it once.

The motivating problem is, when we pass -target-features +tagged-globals
as well as -fsanitize=hwaddress, which adds a second copy, the module
is incompatible with one built with only one -target-features +tagged-globals.


Full diff: https://github.com/llvm/llvm-project/pull/187614.diff

2 Files Affected:

  • (modified) clang/lib/Serialization/ASTReader.cpp (+3)
  • (modified) clang/test/Modules/merge-target-features.cpp (+21)
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 03b1b02859b81..db4fa68f6db08 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -495,7 +495,10 @@ static bool checkTargetOptions(const TargetOptions &TargetOpts,
   SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
                                          TargetOpts.FeaturesAsWritten.end());
   llvm::sort(ExistingFeatures);
+  ExistingFeatures.erase(llvm::unique(ExistingFeatures),
+                         ExistingFeatures.end());
   llvm::sort(ReadFeatures);
+  ReadFeatures.erase(llvm::unique(ReadFeatures), ReadFeatures.end());
 
   // We compute the set difference in both directions explicitly so that we can
   // diagnose the differences differently.
diff --git a/clang/test/Modules/merge-target-features.cpp b/clang/test/Modules/merge-target-features.cpp
index 73474e1388fb6..01d38a1eb0d13 100644
--- a/clang/test/Modules/merge-target-features.cpp
+++ b/clang/test/Modules/merge-target-features.cpp
@@ -10,6 +10,15 @@
 // RUN:   -target-cpu i386 -target-feature +sse2 \
 // RUN:   Inputs/merge-target-features/module.modulemap
 //
+// 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-double.pcm \
+// RUN:   -triple i386-unknown-unknown \
+// RUN:   -target-cpu i386 -target-feature +sse2 -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 \
@@ -60,6 +69,18 @@
 // MISMATCH: error: precompiled file '{{.*}}foo.pcm' was compiled with the target feature '+sse2' but the current translation unit is not
 // MISMATCH: error: current translation unit is compiled with the target feature '+cx16' but the precompiled file '{{.*}}foo.pcm' was not
 // MISMATCH: error: {{.*}} configuration mismatch
+//
+// 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:   -fmodule-map-file=Inputs/merge-target-features/module.modulemap \
+// RUN:   -fmodule-file=%t/foo-double.pcm \
+// RUN:   -triple i386-unknown-unknown \
+// RUN:   -target-cpu i386 -target-feature +sse2 \
+// RUN:   -fsyntax-only merge-target-features.cpp 2>&1 \
+// RUN:   | FileCheck --allow-empty --check-prefix=DOUBLE %s
+// DOUBLE-NOT: error:
 
 #include "foo.h"
 

@fmayer fmayer requested a review from jansvoboda11 March 20, 2026 00:30
@fmayer

fmayer commented Mar 20, 2026

Copy link
Copy Markdown
Contributor Author

Actually, there are more problems around how we handle + and - here.. Will re-send once I also addressed those

@fmayer fmayer marked this pull request as draft March 20, 2026 01:02
@fmayer fmayer marked this pull request as ready for review March 20, 2026 02:01
@fmayer

fmayer commented Mar 20, 2026

Copy link
Copy Markdown
Contributor Author

Actually, let's take it one at a time and fix the other problems later.

@fmayer fmayer requested review from Bigcheese and benlangmuir March 23, 2026 23:05
@fmayer fmayer requested a review from ChuanqiXu9 March 31, 2026 18:15
Comment on lines 497 to +501
llvm::sort(ExistingFeatures);
ExistingFeatures.erase(llvm::unique(ExistingFeatures),
ExistingFeatures.end());
llvm::sort(ReadFeatures);
ReadFeatures.erase(llvm::unique(ReadFeatures), ReadFeatures.end());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer we unique these during AST writing, or even in the CompilerInvocation directly. That would also handle the case for dependency scanning.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #187624 (comment) for the reasoning I did it like this. I don't have strong feelings but wanted to do the minimal change here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess implicit in this was: I don't think we should dedup in a member called AsWritten

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to remove the AsWritten member entirely, perform this canonicalization during command-line parsing and switch to using Features everywhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in the linked comment, that is an option but makes the error messages more verbose

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why? Do targets inject features enabled by default into TargetOptions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my (cursory) understanding is that e.g. +sse2 also implicitly +sse

@fmayer fmayer requested a review from Bigcheese April 1, 2026 18:14
@fmayer

fmayer commented Apr 7, 2026

Copy link
Copy Markdown
Contributor Author

Ping

@fmayer fmayer merged commit e090c86 into main Apr 8, 2026
15 checks passed
@fmayer fmayer deleted the users/fmayer/spr/clang-deduplicate-target-features-for-modules branch April 8, 2026 17:29
YonahGoldberg pushed a commit to YonahGoldberg/llvm-project that referenced this pull request Apr 21, 2026
Previously, double passing a target feature would make the module
incompatible with a compilation unit that only passes it once.

The motivating problem is, when we pass -target-features +tagged-globals
as well as -fsanitize=hwaddress, which adds a second copy, the module
is incompatible with one built with only one `-target-features
+tagged-globals`.
vikramRH pushed a commit to ROCm/llvm-project that referenced this pull request Apr 22, 2026
Previously, double passing a target feature would make the module
incompatible with a compilation unit that only passes it once.

The motivating problem is, when we pass -target-features +tagged-globals
as well as -fsanitize=hwaddress, which adds a second copy, the module
is incompatible with one built with only one `-target-features
+tagged-globals`.
zwu-2025 pushed a commit to zwu-2025/llvm-project that referenced this pull request May 17, 2026
Previously, double passing a target feature would make the module
incompatible with a compilation unit that only passes it once.

The motivating problem is, when we pass -target-features +tagged-globals
as well as -fsanitize=hwaddress, which adds a second copy, the module
is incompatible with one built with only one `-target-features
+tagged-globals`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants