Skip to content

Commit

Permalink
[clang][alias|ifunc]: Add a diagnostic for mangled names
Browse files Browse the repository at this point in the history
When an alias or ifunc attribute refers to a function name that is
mangled, a diagnostic is emitted to suggest the mangled name as a
replacement for the given function name for every matching name in the
current TU.

Fixes #59164

Differential Revision: https://reviews.llvm.org/D143803
  • Loading branch information
dc03 authored and Erich Keane committed Mar 6, 2023
1 parent 38c85a4 commit 9306ef9
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 8 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ Improvements to Clang's diagnostics
``-Wno-deprecated-this-capture``.
- Clang had failed to emit some ``-Wundefined-internal`` for members of a local
class if that class was first introduced with a forward declaration.
- Diagnostic notes and fix-its are now generated for ``ifunc``/``alias`` attributes
which point to functions whose names are mangled.

Bug Fixes in This Version
-------------------------
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ def err_avx_calling_convention : Error<warn_avx_calling_convention.Summary>;
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<
"the %select{function or variable|function}0 specified in an %select{alias|ifunc}1 must refer to its mangled name">;
def note_alias_mangled_name_alternative: Note<
"function by that name is mangled as \"%0\"">;
def warn_alias_to_weak_alias : Warning<
"%select{alias|ifunc}2 will always resolve to %0 even if weak definition of "
"%1 is overridden">,
Expand Down
34 changes: 27 additions & 7 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,11 @@ static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) {
return FinalGV;
}

static bool checkAliasedGlobal(DiagnosticsEngine &Diags,
SourceLocation Location, bool IsIFunc,
const llvm::GlobalValue *Alias,
const llvm::GlobalValue *&GV) {
static bool checkAliasedGlobal(
DiagnosticsEngine &Diags, SourceLocation Location, bool IsIFunc,
const llvm::GlobalValue *Alias, const llvm::GlobalValue *&GV,
const llvm::MapVector<GlobalDecl, StringRef> &MangledDeclNames,
SourceRange AliasRange) {
GV = getAliasedGlobal(Alias);
if (!GV) {
Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc;
Expand All @@ -350,6 +351,22 @@ static bool checkAliasedGlobal(DiagnosticsEngine &Diags,

if (GV->isDeclaration()) {
Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc;
Diags.Report(Location, diag::note_alias_requires_mangled_name)
<< 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<NamedDecl>(Decl.getDecl())) {
if (ND->getName() == GV->getName()) {
Diags.Report(Location, diag::note_alias_mangled_name_alternative)
<< Name
<< FixItHint::CreateReplacement(
AliasRange,
(Twine(IsIFunc ? "ifunc" : "alias") + "(\"" + Name + "\")")
.str());
}
}
}
return false;
}

Expand Down Expand Up @@ -381,16 +398,19 @@ void CodeGenModule::checkAliases() {
for (const GlobalDecl &GD : Aliases) {
const auto *D = cast<ValueDecl>(GD.getDecl());
SourceLocation Location;
SourceRange Range;
bool IsIFunc = D->hasAttr<IFuncAttr>();
if (const Attr *A = D->getDefiningAttr())
if (const Attr *A = D->getDefiningAttr()) {
Location = A->getLocation();
else
Range = A->getRange();
} else
llvm_unreachable("Not an alias or ifunc?");

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, Range)) {
Error = true;
continue;
}
Expand Down
27 changes: 27 additions & 0 deletions clang/test/CodeGen/alias.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %clang_cc1 -triple x86_64-linux -verify -emit-llvm-only %s
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %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 {{must refer to its mangled name}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:47}:"alias(\"_Z8f1_ifuncv\")"

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 {{must refer to its mangled name}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:40-[[@LINE-4]]:69}:"alias(\"_Z20f6_resolver_resolverv\")"
void f6(void) __attribute__((alias("f6_resolver")));
// expected-error@-1 {{alias must point to a defined variable or function}}
// expected-note@-2 {{must refer to its mangled name}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:50}:"alias(\"_Z11f6_resolverv\")"

__attribute__((unused, alias("resolver"), deprecated("hahahaha, isn't C great?")))
void func();
// expected-error@-2 {{alias must point to a defined variable or function}}
// expected-note@-3 {{must refer to its mangled name}}

1 change: 1 addition & 0 deletions clang/test/CodeGen/attr-ifunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ void bar(void) __attribute__((ifunc("foo")));
void *f1_ifunc(void);
void f1(void) __attribute__((ifunc("f1_ifunc")));
// expected-error@-1 {{ifunc must point to a defined function}}
// expected-note@-2 {{must refer to its mangled name}}

void *f2_a(void) __attribute__((alias("f2_b")));
void *f2_b(void) __attribute__((ifunc("f2_a")));
Expand Down
27 changes: 27 additions & 0 deletions clang/test/CodeGen/attr-ifunc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %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 {{must refer to its mangled name}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:47}:"ifunc(\"_Z8f1_ifuncv\")"

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 {{must refer to its mangled name}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:40-[[@LINE-4]]:69}:"ifunc(\"_Z20f6_resolver_resolverv\")"
void f6(void) __attribute__((ifunc("f6_resolver")));
// expected-error@-1 {{ifunc must point to a defined function}}
// expected-note@-2 {{must refer to its mangled name}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:50}:"ifunc(\"_Z11f6_resolverv\")"

__attribute__((unused, ifunc("resolver"), deprecated("hahahaha, isn't C great?")))
void func();
// expected-error@-2 {{ifunc must point to a defined function}}
// expected-note@-3 {{must refer to its mangled name}}

6 changes: 5 additions & 1 deletion clang/test/Sema/attr-alias-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ void g1(void) {
}

void f2(void) __attribute__((alias("g2"))); // expected-error {{alias must point to a defined variable or function}}

// expected-note@-1 {{must refer to its mangled name}}

void f3(void) __attribute__((alias("g3"))); // expected-error {{alias must point to a defined variable or function}}
// expected-note@-1 {{must refer to its mangled name}}
void g3(void);


Expand Down Expand Up @@ -46,11 +47,14 @@ extern int a1 __attribute__((alias("b1")));
int b1 = 42;

extern int a2 __attribute__((alias("b2"))); // expected-error {{alias must point to a defined variable or function}}
// expected-note@-1 {{must refer to its mangled name}}

extern int a3 __attribute__((alias("b3"))); // expected-error {{alias must point to a defined variable or function}}
// expected-note@-1 {{must refer to its mangled name}}
extern int b3;

extern int a4 __attribute__((alias("b4"))); // expected-error {{alias must point to a defined variable or function}}
// expected-note@-1 {{must refer to its mangled name}}
typedef int b4;

void test2_bar() {}
Expand Down
6 changes: 6 additions & 0 deletions clang/test/SemaCXX/externc-ifunc-resolver.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-linux-gnu -verify %s
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s

extern "C" {
__attribute__((used)) static void *resolve_foo() { return 0; }
Expand All @@ -12,5 +13,10 @@ __attribute__((used)) static void *resolve_foo() { return 0; }
// some way to improve this diagnostic (likely by diagnosing when we decide
// this case suppresses alias creation).
__attribute__((ifunc("resolve_foo"))) void foo(); // expected-error{{ifunc must point to a defined function}}
// expected-note@-1 {{must refer to its mangled name}}
// expected-note@-2 {{function by that name is mangled as}}
// expected-note@-3 {{function by that name is mangled as}}
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:16-[[@LINE-4]]:36}:"ifunc(\"_ZL11resolve_foov\")"
// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:16-[[@LINE-5]]:36}:"ifunc(\"_ZN2NSL11resolve_fooEv\")"
}

0 comments on commit 9306ef9

Please sign in to comment.