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

Igor Kudrin via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 16 18:02:06 PDT 2026


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

>From d5ecddba24277a2c34b2d831eb6157dc74166bab Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Mon, 13 Apr 2026 13:58:39 -0700
Subject: [PATCH 1/4] [Clang][CodeGen] Report when an alias points to an
 incompatible target

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/Basic/DiagnosticFrontendKinds.td    |  6 +++
 clang/lib/CodeGen/CodeGenModule.cpp           | 43 +++++++++++++++++++
 clang/test/CodeGen/alias.c                    |  2 +-
 clang/test/Sema/attr-alias-elf.c              | 30 +++++++++++++
 4 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 62b74574102e4..5d10cb3ce26f2 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -354,6 +354,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 79c98f82a766f..557ae9bad0174 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -804,6 +804,49 @@ void CodeGenModule::checkAliases() {
       continue;
     }
 
+    if (!IsIFunc) {
+      // Function declarations can only alias functions (including IFUNCs).
+      // Similarly, variable declarations can only alias variables.
+      if (isa<FunctionDecl>(D) !=
+          (isa<llvm::Function>(GV) || isa<llvm::GlobalIFunc>(GV))) {
+        GlobalDecl AliaseeGD = getMangledNameDecl(GV->getName());
+        assert(AliaseeGD);
+        Diags.Report(Location, diag::err_alias_between_function_and_variable)
+            << isa<FunctionDecl>(D);
+        Diags.Report(AliaseeGD.getDecl()->getLocation(),
+                     diag::note_aliasee_declaration);
+        Error = true;
+        continue;
+      }
+
+      auto shouldReportTypeMismatch = [&]() {
+        llvm::Type *AliasTy = Alias->getValueType();
+        llvm::Type *AliaseeTy = GV->getValueType();
+        // Same types, nothing to report.
+        if (AliasTy == AliaseeTy)
+          return false;
+        // Only report functions.
+        // Type mismatches for variables can be intentional.
+        auto *AliasFTy = dyn_cast<llvm::FunctionType>(AliasTy);
+        auto *AliaseeFTy = dyn_cast<llvm::FunctionType>(AliaseeTy);
+        if (!AliasFTy || !AliaseeFTy)
+          return false;
+        // Only report aliases with unspecified parameter lists if the return
+        // types do not match.
+        if (isa<FunctionNoProtoType>(D->getType().getTypePtr()))
+          return AliasFTy->getReturnType() != AliaseeFTy->getReturnType();
+        return true;
+      };
+      if (shouldReportTypeMismatch()) {
+        GlobalDecl AliaseeGD = getMangledNameDecl(GV->getName());
+        assert(AliaseeGD);
+        Diags.Report(Location, diag::warn_alias_type_mismatch)
+            << D->getType() << cast<ValueDecl>(AliaseeGD.getDecl())->getType();
+        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..c46de4b3e6ebc 100644
--- a/clang/test/Sema/attr-alias-elf.c
+++ b/clang/test/Sema/attr-alias-elf.c
@@ -71,3 +71,33 @@ 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)'}}

>From 0e6dd64e0767cfff403a6e7260e1cb60e1443c88 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 16 Apr 2026 12:55:10 -0700
Subject: [PATCH 2/4] fixup: suppress a warning in dfsan_custom.cpp

---
 compiler-rt/lib/dfsan/dfsan_custom.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

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 9099e331c60d9881dc795fe066e18c6c0893f6b2 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 16 Apr 2026 17:38:14 -0700
Subject: [PATCH 3/4] fixup: isa<llvm::Function, llvm::GlobalIFunc>(GV)

---
 clang/lib/CodeGen/CodeGenModule.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 557ae9bad0174..4185eecbbb580 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -807,8 +807,7 @@ void CodeGenModule::checkAliases() {
     if (!IsIFunc) {
       // Function declarations can only alias functions (including IFUNCs).
       // Similarly, variable declarations can only alias variables.
-      if (isa<FunctionDecl>(D) !=
-          (isa<llvm::Function>(GV) || isa<llvm::GlobalIFunc>(GV))) {
+      if (isa<FunctionDecl>(D) != isa<llvm::Function, llvm::GlobalIFunc>(GV)) {
         GlobalDecl AliaseeGD = getMangledNameDecl(GV->getName());
         assert(AliaseeGD);
         Diags.Report(Location, diag::err_alias_between_function_and_variable)

>From f2c968be4c5f6240c43ff7d858e0010a5a8eac54 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Thu, 16 Apr 2026 18:00:20 -0700
Subject: [PATCH 4/4] fixup: update ReleaseNotes.rst

---
 clang/docs/ReleaseNotes.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5edec5f04e976..c99339ecae4d8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -382,6 +382,10 @@ Improvements to Clang's diagnostics
   code can automatically be made portable to other host platforms that don't
   support backslashes.
 
+- 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
 ----------------------------------
 



More information about the cfe-commits mailing list