[clang] [compiler-rt] Reland "[Clang][CodeGen] Report when an alias points to an incompatible target" (PR #195550)

Igor Kudrin via cfe-commits cfe-commits at lists.llvm.org
Thu May 7 00:38:29 PDT 2026


https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/195550

>From 79f90fe9a002fdd808620cbe2e5893a8e5b7ada0 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 24 Apr 2026 19:08:10 -0700
Subject: [PATCH 1/4] Reland "[Clang][CodeGen] Report when an alias points to
 an incompatible target"

This relands #192397, which was reverted in #194106. The new version
includes the following fixes:
- Set an explicit triple in the `attr-alias.m` test because aliases are
  not supported on Darwin.
- Relax the check to only diagnose mismatches in return types and
  parameter lists, while ignoring exception specifications and other
  attributes.

Original description follows:

Add checks to ensure that an alias and its target have compatible types:
- Generate an error if a function alias points to a variable or vice
  versa.
- Issue a warning for mismatches in function types.
- Ignore type discrepancies for variables.

This behavior aligns with similar diagnostics in GCC.

Resolves: #47301
---
 clang/docs/ReleaseNotes.rst                   |  4 ++
 .../clang/Basic/DiagnosticFrontendKinds.td    |  6 ++
 clang/lib/CodeGen/CodeGenModule.cpp           | 64 +++++++++++++++++++
 clang/test/CodeGen/alias.c                    |  2 +-
 clang/test/Sema/attr-alias-elf.c              | 40 ++++++++++++
 clang/test/SemaCXX/attr-alias.cpp             | 13 ++++
 clang/test/SemaObjC/attr-alias.m              |  6 ++
 compiler-rt/lib/dfsan/dfsan_custom.cpp        |  7 +-
 8 files changed, 140 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/SemaCXX/attr-alias.cpp
 create mode 100644 clang/test/SemaObjC/attr-alias.m

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7027a3d836cd6..8351ef2a61c62 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -468,6 +468,10 @@ Improvements to Clang's diagnostics
 
 - Removed the body of lambdas from some diagnostic messages.
 
+- Clang now errors when a function declaration aliases a variable or vice versa. (#GH192397)
+
+- Added ``-Wattribute-alias`` to diagnose type mismatches between an alias and its aliased function. (#GH192397)
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index f384a97b6825e..3d5da95de99ee 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -359,6 +359,12 @@ def err_non_default_visibility_dllimport : Error<
   "non-default visibility cannot be applied to 'dllimport' declaration">;
 def err_ifunc_resolver_return : Error<
   "ifunc resolver function must return a pointer">;
+def err_alias_between_function_and_variable : Error<
+  "cannot alias a %select{function|variable}0 with a %select{variable|function}0">;
+def note_aliasee_declaration: Note<"aliasee is declared here">;
+def warn_alias_type_mismatch : Warning<
+  "alias and aliasee have different types %0 and %1">,
+  InGroup<DiagGroup<"attribute-alias">>;
 
 def warn_atomic_op_misaligned : Warning<
   "misaligned atomic operation may incur "
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 20a28c39af88a..735f53a815fb7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -804,6 +804,70 @@ void CodeGenModule::checkAliases() {
       continue;
     }
 
+    if (!IsIFunc) {
+      GlobalDecl AliaseeGD;
+      if (!lookupRepresentativeDecl(GV->getName(), AliaseeGD) ||
+          !isa<VarDecl, FunctionDecl>(AliaseeGD.getDecl())) {
+        Diags.Report(Location, diag::err_alias_to_undefined)
+            << IsIFunc << IsIFunc;
+        Error = true;
+        continue;
+      }
+
+      bool aliasIsFuncDecl = isa<FunctionDecl>(D);
+      bool aliaseeIsFunc = isa<llvm::Function, llvm::GlobalIFunc>(GV);
+      // Function declarations can only alias functions (including IFUNCs).
+      // Similarly, variable declarations can only alias variables.
+      if (aliasIsFuncDecl != aliaseeIsFunc) {
+        Diags.Report(Location, diag::err_alias_between_function_and_variable)
+            << aliasIsFuncDecl;
+        Diags.Report(AliaseeGD.getDecl()->getLocation(),
+                     diag::note_aliasee_declaration);
+        Error = true;
+        continue;
+      }
+
+      // Only report functions.
+      // Type mismatches for variables can be intentional.
+      if (aliasIsFuncDecl && aliaseeIsFunc) {
+        QualType AliasTy = D->getType();
+        QualType AliaseeTy = cast<ValueDecl>(AliaseeGD.getDecl())->getType();
+        auto shouldReportTypeMismatch = [&]() {
+          const auto *AliasFTy =
+              AliasTy.getCanonicalType()->getAs<FunctionType>();
+          const auto *AliaseeFTy =
+              AliaseeTy.getCanonicalType()->getAs<FunctionType>();
+          assert(AliasFTy && AliaseeFTy);
+          if (!Context.typesAreCompatible(AliasFTy->getReturnType(),
+                                          AliaseeFTy->getReturnType()))
+            return true;
+          const auto *AliasFPTy = dyn_cast<FunctionProtoType>(AliasFTy);
+          // Do not report aliases with unspecified parameter lists.
+          if (!AliasFPTy)
+            return false;
+          // Report if the parameter lists are different. Any other mismatches,
+          // such as in exception specifications, are ignored.
+          const auto *AliaseeFPTy = dyn_cast<FunctionProtoType>(AliaseeFTy);
+          if (!AliaseeFPTy)
+            return true;
+          if (AliasFPTy->getNumParams() != AliaseeFPTy->getNumParams() ||
+              AliasFPTy->isVariadic() != AliaseeFPTy->isVariadic())
+            return true;
+          for (unsigned i = 0; i < AliasFPTy->getNumParams(); ++i)
+            if (!Context.typesAreCompatible(AliasFPTy->getParamType(i),
+                                            AliaseeFPTy->getParamType(i)))
+              return true;
+          return false;
+        };
+        if (shouldReportTypeMismatch()) {
+          Diags.Report(Location, diag::warn_alias_type_mismatch)
+              << AliasTy << AliaseeTy;
+          Diags.Report(AliaseeGD.getDecl()->getLocation(),
+                       diag::note_aliasee_declaration);
+        }
+      }
+    }
+
     if (getContext().getTargetInfo().getTriple().isOSAIX())
       if (const llvm::GlobalVariable *GVar =
               dyn_cast<const llvm::GlobalVariable>(GV))
diff --git a/clang/test/CodeGen/alias.c b/clang/test/CodeGen/alias.c
index 9403c55beae0b..f4bc9668e343c 100644
--- a/clang/test/CodeGen/alias.c
+++ b/clang/test/CodeGen/alias.c
@@ -59,7 +59,7 @@ extern void f1(void) __attribute((alias("f0")));
 static inline int foo1() { return 0; }
 // CHECKBASIC-LABEL: define internal i32 @foo1()
 int foo() __attribute__((alias("foo1")));
-int bar() __attribute__((alias("bar1")));
+extern int bar __attribute__((alias("bar1")));
 
 extern int test6();
 void test7() { test6(); }  // test6 is emitted as extern.
diff --git a/clang/test/Sema/attr-alias-elf.c b/clang/test/Sema/attr-alias-elf.c
index d2674d1db0312..e01d684eae5d2 100644
--- a/clang/test/Sema/attr-alias-elf.c
+++ b/clang/test/Sema/attr-alias-elf.c
@@ -71,3 +71,43 @@ void test4_foo() __attribute__((alias("test4_bar")));
 
 int test5_bar = 0;
 extern struct incomplete_type test5_foo __attribute__((alias("test5_bar")));
+
+int test6 = 0;
+// expected-note at -1 {{aliasee is declared here}}
+void test6_alias() __attribute__((alias("test6")));
+// expected-error at -1 {{cannot alias a variable with a function}}
+
+extern int test7_alias __attribute__((alias("test7")));
+// expected-error at -1 {{cannot alias a function with a variable}}
+int test7(int x) { return x * 2; }
+// expected-note at -1 {{aliasee is declared here}}
+
+void *test8_ifunc() { return 0; }
+void test8(void) __attribute__((ifunc("test8_ifunc")));
+// expected-note at -1 {{aliasee is declared here}}
+extern int test8_alias __attribute__((alias("test8")));
+// expected-error at -1 {{cannot alias a function with a variable}}
+
+void test9() {}
+// expected-note at -1 {{aliasee is declared here}}
+int test9_alias() __attribute__((alias("test9")));
+// expected-warning at -1 {{alias and aliasee have different types 'int ()' and 'void ()'}}
+
+// No warning for an alias with unspecified parameters if the return types match.
+int test10(int x, int y) { return x + y; }
+int test10_alias() __attribute__((alias("test10")));
+
+int test11(int x, int y) { return x + y; }
+// expected-note at -1 {{aliasee is declared here}}
+int test11_alias(int x, ...) __attribute__((alias("test11")));
+// expected-warning at -1 {{alias and aliasee have different types 'int (int, ...)' and 'int (int, int)'}}
+
+// No warnings expected when using typedef equivalents.
+typedef int Integer;
+Integer test12(int x) { return x; }
+int test12_alias(Integer) __attribute__((alias("test12")));
+
+// Compiler-generated variables are not valid alias targets.
+char *test13 = "asdf";
+extern char test13_alias[5] __attribute__((alias(".str")));
+// expected-error at -1 {{alias must point to a defined variable or function}}
diff --git a/clang/test/SemaCXX/attr-alias.cpp b/clang/test/SemaCXX/attr-alias.cpp
new file mode 100644
index 0000000000000..bf76e56f7eca4
--- /dev/null
+++ b/clang/test/SemaCXX/attr-alias.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++17 -emit-llvm-only -verify %s
+// expected-no-diagnostics
+
+// Note: this mimics how interceptor functions are defined in the compiler-rt
+// libraries. Despite a declaration in the system header having an exception
+// specification, redeclaring it in the user code does not produce the "missing
+// exception specification" error. Consequently, there should be no warnings
+// about type mismatches for the alias and its aliasee.
+# 1 "attr-alias.h" 1 3
+extern "C" void test1() noexcept(true);
+# 12 "attr-alias.cpp" 2
+extern "C" void test1() __attribute__((alias("test1_aliasee")));
+extern "C" void test1_aliasee() { }
diff --git a/clang/test/SemaObjC/attr-alias.m b/clang/test/SemaObjC/attr-alias.m
new file mode 100644
index 0000000000000..49c92c4436b1b
--- /dev/null
+++ b/clang/test/SemaObjC/attr-alias.m
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fblocks -verify -emit-llvm-only %s
+
+// Compiler-generated functions are not valid alias targets.
+void foo() { void(^myBlock)(void) = ^{ }; }
+void bar() __attribute__((alias("__foo_block_invoke")));
+// expected-error at -1 {{alias must point to a defined variable or function}}
diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp
index b060e5c56edbe..9bb9b07037921 100644
--- a/compiler-rt/lib/dfsan/dfsan_custom.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp
@@ -55,9 +55,14 @@ using namespace __dfsan;
 #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
 
+#define PRAGMA(x) _Pragma(#x)
 #define WRAPPER_ALIAS(fun, real)                                          \
+  PRAGMA(clang diagnostic push)                                           \
+  PRAGMA(clang diagnostic ignored "-Wunknown-warning-option")             \
+  PRAGMA(clang diagnostic ignored "-Wattribute-alias")                    \
   SANITIZER_INTERFACE_ATTRIBUTE void __dfsw_##fun() ALIAS(__dfsw_##real); \
-  SANITIZER_INTERFACE_ATTRIBUTE void __dfso_##fun() ALIAS(__dfso_##real);
+  SANITIZER_INTERFACE_ATTRIBUTE void __dfso_##fun() ALIAS(__dfso_##real); \
+  PRAGMA(clang diagnostic pop)
 
 // Async-safe, non-reentrant spin lock.
 namespace {

>From 7869910087a8dbdc711bce24a5da06551cd7ecac Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Mon, 4 May 2026 19:56:54 -0700
Subject: [PATCH 2/4] fixup: uppercase vars

---
 clang/lib/CodeGen/CodeGenModule.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 735f53a815fb7..bc0b7ec6367d5 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -814,13 +814,13 @@ void CodeGenModule::checkAliases() {
         continue;
       }
 
-      bool aliasIsFuncDecl = isa<FunctionDecl>(D);
-      bool aliaseeIsFunc = isa<llvm::Function, llvm::GlobalIFunc>(GV);
+      bool AliasIsFuncDecl = isa<FunctionDecl>(D);
+      bool AliaseeIsFunc = isa<llvm::Function, llvm::GlobalIFunc>(GV);
       // Function declarations can only alias functions (including IFUNCs).
       // Similarly, variable declarations can only alias variables.
-      if (aliasIsFuncDecl != aliaseeIsFunc) {
+      if (AliasIsFuncDecl != AliaseeIsFunc) {
         Diags.Report(Location, diag::err_alias_between_function_and_variable)
-            << aliasIsFuncDecl;
+            << AliasIsFuncDecl;
         Diags.Report(AliaseeGD.getDecl()->getLocation(),
                      diag::note_aliasee_declaration);
         Error = true;
@@ -829,7 +829,7 @@ void CodeGenModule::checkAliases() {
 
       // Only report functions.
       // Type mismatches for variables can be intentional.
-      if (aliasIsFuncDecl && aliaseeIsFunc) {
+      if (AliasIsFuncDecl && AliaseeIsFunc) {
         QualType AliasTy = D->getType();
         QualType AliaseeTy = cast<ValueDecl>(AliaseeGD.getDecl())->getType();
         auto shouldReportTypeMismatch = [&]() {

>From 731f15ac42d5296d2c253f234398869533792d26 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Mon, 4 May 2026 20:47:01 -0700
Subject: [PATCH 3/4] fixup: only diagnose no-prototype aliasee if return types
 mismatch

---
 clang/lib/CodeGen/CodeGenModule.cpp |  6 ++----
 clang/test/Sema/attr-alias-elf.c    | 18 +++++++++++-------
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index bc0b7ec6367d5..6bc36dc837ce1 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -842,14 +842,12 @@ void CodeGenModule::checkAliases() {
                                           AliaseeFTy->getReturnType()))
             return true;
           const auto *AliasFPTy = dyn_cast<FunctionProtoType>(AliasFTy);
+          const auto *AliaseeFPTy = dyn_cast<FunctionProtoType>(AliaseeFTy);
           // Do not report aliases with unspecified parameter lists.
-          if (!AliasFPTy)
+          if (!AliasFPTy || !AliaseeFPTy)
             return false;
           // Report if the parameter lists are different. Any other mismatches,
           // such as in exception specifications, are ignored.
-          const auto *AliaseeFPTy = dyn_cast<FunctionProtoType>(AliaseeFTy);
-          if (!AliaseeFPTy)
-            return true;
           if (AliasFPTy->getNumParams() != AliaseeFPTy->getNumParams() ||
               AliasFPTy->isVariadic() != AliaseeFPTy->isVariadic())
             return true;
diff --git a/clang/test/Sema/attr-alias-elf.c b/clang/test/Sema/attr-alias-elf.c
index e01d684eae5d2..e24d935f70ed9 100644
--- a/clang/test/Sema/attr-alias-elf.c
+++ b/clang/test/Sema/attr-alias-elf.c
@@ -97,17 +97,21 @@ int test9_alias() __attribute__((alias("test9")));
 int test10(int x, int y) { return x + y; }
 int test10_alias() __attribute__((alias("test10")));
 
-int test11(int x, int y) { return x + y; }
+// No warning for an alias target with unspecified parameters if the return types match.
+int test11() { return 7; }
+int test11_alias(int x) __attribute__((alias("test11")));
+
+int test12(int x, int y) { return x + y; }
 // expected-note at -1 {{aliasee is declared here}}
-int test11_alias(int x, ...) __attribute__((alias("test11")));
+int test12_alias(int x, ...) __attribute__((alias("test12")));
 // expected-warning at -1 {{alias and aliasee have different types 'int (int, ...)' and 'int (int, int)'}}
 
-// No warnings expected when using typedef equivalents.
+// No warning when using typedef equivalents.
 typedef int Integer;
-Integer test12(int x) { return x; }
-int test12_alias(Integer) __attribute__((alias("test12")));
+Integer test13(int x) { return x; }
+int test13_alias(Integer) __attribute__((alias("test13")));
 
 // Compiler-generated variables are not valid alias targets.
-char *test13 = "asdf";
-extern char test13_alias[5] __attribute__((alias(".str")));
+char *test14 = "asdf";
+extern char test14_alias[5] __attribute__((alias(".str")));
 // expected-error at -1 {{alias must point to a defined variable or function}}

>From 38117fd91d6bb5b1290028f4e49d784e896e3571 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 7 May 2026 00:20:35 -0700
Subject: [PATCH 4/4] fixup: unprototyped vs variadic

---
 clang/lib/CodeGen/CodeGenModule.cpp |  4 ++++
 clang/test/Sema/attr-alias-elf.c    | 11 +++++++++++
 2 files changed, 15 insertions(+)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 6bc36dc837ce1..c71cf011fa074 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -843,6 +843,10 @@ void CodeGenModule::checkAliases() {
             return true;
           const auto *AliasFPTy = dyn_cast<FunctionProtoType>(AliasFTy);
           const auto *AliaseeFPTy = dyn_cast<FunctionProtoType>(AliaseeFTy);
+          // Report variadic vs no-prototype.
+          if ((AliasFPTy && AliasFPTy->isVariadic() && !AliaseeFPTy) ||
+              (AliaseeFPTy && AliaseeFPTy->isVariadic() && !AliasFPTy))
+            return true;
           // Do not report aliases with unspecified parameter lists.
           if (!AliasFPTy || !AliaseeFPTy)
             return false;
diff --git a/clang/test/Sema/attr-alias-elf.c b/clang/test/Sema/attr-alias-elf.c
index e24d935f70ed9..e2d4d41f459ff 100644
--- a/clang/test/Sema/attr-alias-elf.c
+++ b/clang/test/Sema/attr-alias-elf.c
@@ -115,3 +115,14 @@ int test13_alias(Integer) __attribute__((alias("test13")));
 char *test14 = "asdf";
 extern char test14_alias[5] __attribute__((alias(".str")));
 // expected-error at -1 {{alias must point to a defined variable or function}}
+
+// Unprototyped functions should not alias variadic function and vice versa.
+int test15() { return 9; }
+// expected-note at -1 {{aliasee is declared here}}
+int test15_alias(int x, ...) __attribute__((alias("test15")));
+// expected-warning at -1 {{alias and aliasee have different types 'int (int, ...)' and 'int ()'}}
+
+void test16(int x, ...) { }
+// expected-note at -1 {{aliasee is declared here}}
+void test16_alias() __attribute__((alias("test16")));
+// expected-warning at -1 {{alias and aliasee have different types 'void ()' and 'void (int, ...)'}}



More information about the cfe-commits mailing list