Skip to content

Conversation

smeenai
Copy link
Collaborator

@smeenai smeenai commented Sep 27, 2025

There's build setups where source file names aren't necessarily unique
(e.g. the same source files can be used for multiple targets) but output
paths are. It's theoretically possible to get the build system to pass
-funique-source-file-identifier with the output path, but it can also
be quite complicated to do so. Introduce a driver option that specifies
the output path as the unique source identifier to support this.

There's build setups where source file names aren't necessarily unique
(e.g. the same source files can be used for multiple targets) but output
paths are. It's theoretically possible to get the build system to pass
`-funique-source-file-identifier` with the output path, but it can also
be quite complicated to do so. Introduce a driver option that specifies
the output path as the unique source identifier to support this.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 27, 2025

@llvm/pr-subscribers-clang

Author: Shoaib Meenai (smeenai)

Changes

There's build setups where source file names aren't necessarily unique
(e.g. the same source files can be used for multiple targets) but output
paths are. It's theoretically possible to get the build system to pass
-funique-source-file-identifier with the output path, but it can also
be quite complicated to do so. Introduce a driver option that specifies
the output path as the unique source identifier to support this.


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

5 Files Affected:

  • (modified) clang/docs/UsersManual.rst (+11-5)
  • (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+3)
  • (modified) clang/include/clang/Driver/Options.td (+2)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+13-3)
  • (modified) clang/test/Driver/unique-source-file-names.c (+6)
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index a8bbf146431ea..674af675a4336 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2341,10 +2341,11 @@ are listed below.
 
    When enabled, allows the compiler to assume that each object file
    passed to the linker has a unique identifier. The identifier for
-   an object file is either the source file path or the value of the
-   argument `-funique-source-file-identifier` if specified. This is
-   useful for reducing link times when doing ThinLTO in combination with
-   whole-program devirtualization or CFI.
+   an object file is either the source file path, the output file path
+   if the ``-funique-source-file-output-paths`` argument is passed, or
+   the value of the argument ``-funique-source-file-identifier`` if
+   specified. This is useful for reducing link times when doing ThinLTO
+   in combination with whole-program devirtualization or CFI.
 
    The full source path or identifier passed to the compiler must be
    unique. This means that, for example, the following is a usage error:
@@ -2371,9 +2372,14 @@ are listed below.
 
 .. option:: -funique-source-file-identifier=IDENTIFIER
 
-   Used with `-funique-source-file-names` to specify a source file
+   Used with ``-funique-source-file-names`` to specify a source file
    identifier.
 
+.. option:: -funique-source-file-output-paths
+
+   Used with ``-funique-source-file-names`` to specify the output path
+   as the source file identifier.
+
 .. option:: -fforce-emit-vtables
 
    In order to improve devirtualization, forces emitting of vtables even in
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index ceb69091b2a51..4af84703c469c 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -890,4 +890,7 @@ def warn_drv_gcc_install_dir_libstdcxx : Warning<
     "future releases of the clang compiler will prefer GCC installations "
     "containing libstdc++ include directories; '%0' would be chosen over '%1'">,
     InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
+
+def err_drv_no_output_filename : Error<
+  "option '%0' requires an output file name">;
 }
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6245cf33a0719..3d173785b8c6e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4354,6 +4354,8 @@ def unique_source_file_identifier_EQ: Joined<["-"], "funique-source-file-identif
   HelpText<"Specify the source file identifier for -funique-source-file-names; "
            "uses the source file path if not specified">,
   MarshallingInfoString<CodeGenOpts<"UniqueSourceFileIdentifier">>;
+def funique_source_file_output_paths: Joined<["-"], "funique-source-file-output-paths">, Group<f_Group>,
+  HelpText<"Use the output path as the source file identifier for -funique-source-file-names">;
 def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
 def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
 def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index adaa6b3005577..bf9b49670bfd1 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7578,11 +7578,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (Args.hasFlag(options::OPT_funique_source_file_names,
                    options::OPT_fno_unique_source_file_names, false)) {
-    if (Arg *A = Args.getLastArg(options::OPT_unique_source_file_identifier_EQ))
-      A->render(Args, CmdArgs);
-    else
+    Arg *A = Args.getLastArg(options::OPT_unique_source_file_identifier_EQ,
+                             options::OPT_funique_source_file_output_paths);
+    if (!A) {
       CmdArgs.push_back(Args.MakeArgString(
           Twine("-funique-source-file-identifier=") + Input.getBaseInput()));
+    } else if (A->getOption().matches(
+                   options::OPT_funique_source_file_output_paths)) {
+      if (Output.isFilename())
+        CmdArgs.push_back(Args.MakeArgString(
+            Twine("-funique-source-file-identifier=") + Output.getFilename()));
+      else
+        D.Diag(diag::err_drv_no_output_filename) << A->getSpelling();
+    } else {
+      A->render(Args, CmdArgs);
+    }
   }
 
   // Setup statistics file output.
diff --git a/clang/test/Driver/unique-source-file-names.c b/clang/test/Driver/unique-source-file-names.c
index 0dc71345d745c..48403327686b7 100644
--- a/clang/test/Driver/unique-source-file-names.c
+++ b/clang/test/Driver/unique-source-file-names.c
@@ -9,3 +9,9 @@
 
 // ID: "-cc1"
 // ID: "-funique-source-file-identifier=foo"
+
+// RUN: %clang -funique-source-file-names -funique-source-file-output-paths -o out.o -c -### %s 2> %t
+// RUN: FileCheck --check-prefix=OUTPUT < %t %s
+
+// OUTPUT: "-cc1"
+// OUTPUT: "-funique-source-file-identifier=out.o"

@llvmbot
Copy link
Member

llvmbot commented Sep 27, 2025

@llvm/pr-subscribers-clang-driver

Author: Shoaib Meenai (smeenai)

Changes

There's build setups where source file names aren't necessarily unique
(e.g. the same source files can be used for multiple targets) but output
paths are. It's theoretically possible to get the build system to pass
-funique-source-file-identifier with the output path, but it can also
be quite complicated to do so. Introduce a driver option that specifies
the output path as the unique source identifier to support this.


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

5 Files Affected:

  • (modified) clang/docs/UsersManual.rst (+11-5)
  • (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+3)
  • (modified) clang/include/clang/Driver/Options.td (+2)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+13-3)
  • (modified) clang/test/Driver/unique-source-file-names.c (+6)
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index a8bbf146431ea..674af675a4336 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2341,10 +2341,11 @@ are listed below.
 
    When enabled, allows the compiler to assume that each object file
    passed to the linker has a unique identifier. The identifier for
-   an object file is either the source file path or the value of the
-   argument `-funique-source-file-identifier` if specified. This is
-   useful for reducing link times when doing ThinLTO in combination with
-   whole-program devirtualization or CFI.
+   an object file is either the source file path, the output file path
+   if the ``-funique-source-file-output-paths`` argument is passed, or
+   the value of the argument ``-funique-source-file-identifier`` if
+   specified. This is useful for reducing link times when doing ThinLTO
+   in combination with whole-program devirtualization or CFI.
 
    The full source path or identifier passed to the compiler must be
    unique. This means that, for example, the following is a usage error:
@@ -2371,9 +2372,14 @@ are listed below.
 
 .. option:: -funique-source-file-identifier=IDENTIFIER
 
-   Used with `-funique-source-file-names` to specify a source file
+   Used with ``-funique-source-file-names`` to specify a source file
    identifier.
 
+.. option:: -funique-source-file-output-paths
+
+   Used with ``-funique-source-file-names`` to specify the output path
+   as the source file identifier.
+
 .. option:: -fforce-emit-vtables
 
    In order to improve devirtualization, forces emitting of vtables even in
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index ceb69091b2a51..4af84703c469c 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -890,4 +890,7 @@ def warn_drv_gcc_install_dir_libstdcxx : Warning<
     "future releases of the clang compiler will prefer GCC installations "
     "containing libstdc++ include directories; '%0' would be chosen over '%1'">,
     InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
+
+def err_drv_no_output_filename : Error<
+  "option '%0' requires an output file name">;
 }
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6245cf33a0719..3d173785b8c6e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4354,6 +4354,8 @@ def unique_source_file_identifier_EQ: Joined<["-"], "funique-source-file-identif
   HelpText<"Specify the source file identifier for -funique-source-file-names; "
            "uses the source file path if not specified">,
   MarshallingInfoString<CodeGenOpts<"UniqueSourceFileIdentifier">>;
+def funique_source_file_output_paths: Joined<["-"], "funique-source-file-output-paths">, Group<f_Group>,
+  HelpText<"Use the output path as the source file identifier for -funique-source-file-names">;
 def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
 def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
 def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index adaa6b3005577..bf9b49670bfd1 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7578,11 +7578,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (Args.hasFlag(options::OPT_funique_source_file_names,
                    options::OPT_fno_unique_source_file_names, false)) {
-    if (Arg *A = Args.getLastArg(options::OPT_unique_source_file_identifier_EQ))
-      A->render(Args, CmdArgs);
-    else
+    Arg *A = Args.getLastArg(options::OPT_unique_source_file_identifier_EQ,
+                             options::OPT_funique_source_file_output_paths);
+    if (!A) {
       CmdArgs.push_back(Args.MakeArgString(
           Twine("-funique-source-file-identifier=") + Input.getBaseInput()));
+    } else if (A->getOption().matches(
+                   options::OPT_funique_source_file_output_paths)) {
+      if (Output.isFilename())
+        CmdArgs.push_back(Args.MakeArgString(
+            Twine("-funique-source-file-identifier=") + Output.getFilename()));
+      else
+        D.Diag(diag::err_drv_no_output_filename) << A->getSpelling();
+    } else {
+      A->render(Args, CmdArgs);
+    }
   }
 
   // Setup statistics file output.
diff --git a/clang/test/Driver/unique-source-file-names.c b/clang/test/Driver/unique-source-file-names.c
index 0dc71345d745c..48403327686b7 100644
--- a/clang/test/Driver/unique-source-file-names.c
+++ b/clang/test/Driver/unique-source-file-names.c
@@ -9,3 +9,9 @@
 
 // ID: "-cc1"
 // ID: "-funique-source-file-identifier=foo"
+
+// RUN: %clang -funique-source-file-names -funique-source-file-output-paths -o out.o -c -### %s 2> %t
+// RUN: FileCheck --check-prefix=OUTPUT < %t %s
+
+// OUTPUT: "-cc1"
+// OUTPUT: "-funique-source-file-identifier=out.o"

@smeenai
Copy link
Collaborator Author

smeenai commented Oct 13, 2025

Ping.

@pcc
Copy link
Contributor

pcc commented Oct 13, 2025

What do you think about -funique-output-file-names on its own enabling the unique identifier behavior instead of the new flag having to be specified with -funique-source-file-names? We may also consider removing the -funique-source-file-names requirement for -funique-source-file-identifier=.

@smeenai
Copy link
Collaborator Author

smeenai commented Oct 13, 2025

What do you think about -funique-output-file-names on its own enabling the unique identifier behavior instead of the new flag having to be specified with -funique-source-file-names?

I like that more; I'll rework the diff accordingly.

We may also consider removing the -funique-source-file-names requirement for -funique-source-file-identifier=.

It might be cleaner to do this bit first; I can put that up as a prerequisite PR if that turns out to be the case.

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

Labels

clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants