diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -278,6 +278,8 @@ def err_alias_to_undefined : Error< "%select{alias|ifunc}0 must point to a defined " "%select{variable or |}1function">; +def note_alias_requires_mangled_name : Note< + "'%0' exists as a mangled name, did you mean to use '%1'?">; def warn_alias_to_weak_alias : Warning< "%select{alias|ifunc}2 will always resolve to %0 even if weak definition of " "%1 is overridden">, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -341,7 +341,8 @@ static bool checkAliasedGlobal(DiagnosticsEngine &Diags, SourceLocation Location, bool IsIFunc, const llvm::GlobalValue *Alias, - const llvm::GlobalValue *&GV) { + const llvm::GlobalValue *&GV, + const llvm::MapVector &MangledDeclNames) { GV = getAliasedGlobal(Alias); if (!GV) { Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; @@ -350,6 +351,16 @@ if (GV->isDeclaration()) { Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc; + // Provide a note if the given function is not found and exists as a + // mangled name + for (const auto &[Decl, Name] : MangledDeclNames) { + if (const auto *ND = dyn_cast(Decl.getDecl())) { + if (ND->getName() == GV->getName()) { + Diags.Report(Location, diag::note_alias_requires_mangled_name) + << GV->getName() << Name; + } + } + } return false; } @@ -390,7 +401,8 @@ StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Alias = GetGlobalValue(MangledName); const llvm::GlobalValue *GV = nullptr; - if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV)) { + if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV, + MangledDeclNames)) { Error = true; continue; } diff --git a/clang/test/CodeGen/alias.cpp b/clang/test/CodeGen/alias.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/alias.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s + +void *f1_ifunc(void) { return nullptr; } +void f1(void) __attribute__((alias("f1_ifunc"))); +// expected-error@-1 {{alias must point to a defined variable or function}} +// expected-note@-2 {{exists as a mangled name}} + +void *f6_resolver_resolver(void) { return 0; } +void *f6_resolver(void) __attribute__((alias("f6_resolver_resolver"))); +// expected-error@-1 {{alias must point to a defined variable or function}} +// expected-note@-2 {{exists as a mangled name}} +void f6(void) __attribute__((alias("f6_resolver"))); +// expected-error@-1 {{alias must point to a defined variable or function}} +// expected-note@-2 {{exists as a mangled name}} diff --git a/clang/test/CodeGen/attr-ifunc.cpp b/clang/test/CodeGen/attr-ifunc.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-ifunc.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s + +void *f1_ifunc(void) { return nullptr; } +void f1(void) __attribute__((ifunc("f1_ifunc"))); +// expected-error@-1 {{ifunc must point to a defined function}} +// expected-note@-2 {{exists as a mangled name}} + +void *f6_resolver_resolver(void) { return 0; } +void *f6_resolver(void) __attribute__((ifunc("f6_resolver_resolver"))); +// expected-error@-1 {{ifunc must point to a defined function}} +// expected-note@-2 {{exists as a mangled name}} +void f6(void) __attribute__((ifunc("f6_resolver"))); +// expected-error@-1 {{ifunc must point to a defined function}} +// expected-note@-2 {{exists as a mangled name}}