Skip to content

Commit 9306ef9

Browse files
dc03Erich Keane
authored and
Erich Keane
committed
[clang][alias|ifunc]: Add a diagnostic for mangled names
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
1 parent 38c85a4 commit 9306ef9

File tree

8 files changed

+99
-8
lines changed

8 files changed

+99
-8
lines changed

clang/docs/ReleaseNotes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ Improvements to Clang's diagnostics
157157
``-Wno-deprecated-this-capture``.
158158
- Clang had failed to emit some ``-Wundefined-internal`` for members of a local
159159
class if that class was first introduced with a forward declaration.
160+
- Diagnostic notes and fix-its are now generated for ``ifunc``/``alias`` attributes
161+
which point to functions whose names are mangled.
160162

161163
Bug Fixes in This Version
162164
-------------------------

clang/include/clang/Basic/DiagnosticFrontendKinds.td

+4
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ def err_avx_calling_convention : Error<warn_avx_calling_convention.Summary>;
278278
def err_alias_to_undefined : Error<
279279
"%select{alias|ifunc}0 must point to a defined "
280280
"%select{variable or |}1function">;
281+
def note_alias_requires_mangled_name : Note<
282+
"the %select{function or variable|function}0 specified in an %select{alias|ifunc}1 must refer to its mangled name">;
283+
def note_alias_mangled_name_alternative: Note<
284+
"function by that name is mangled as \"%0\"">;
281285
def warn_alias_to_weak_alias : Warning<
282286
"%select{alias|ifunc}2 will always resolve to %0 even if weak definition of "
283287
"%1 is overridden">,

clang/lib/CodeGen/CodeGenModule.cpp

+27-7
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,11 @@ static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) {
338338
return FinalGV;
339339
}
340340

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

351352
if (GV->isDeclaration()) {
352353
Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc;
354+
Diags.Report(Location, diag::note_alias_requires_mangled_name)
355+
<< IsIFunc << IsIFunc;
356+
// Provide a note if the given function is not found and exists as a
357+
// mangled name.
358+
for (const auto &[Decl, Name] : MangledDeclNames) {
359+
if (const auto *ND = dyn_cast<NamedDecl>(Decl.getDecl())) {
360+
if (ND->getName() == GV->getName()) {
361+
Diags.Report(Location, diag::note_alias_mangled_name_alternative)
362+
<< Name
363+
<< FixItHint::CreateReplacement(
364+
AliasRange,
365+
(Twine(IsIFunc ? "ifunc" : "alias") + "(\"" + Name + "\")")
366+
.str());
367+
}
368+
}
369+
}
353370
return false;
354371
}
355372

@@ -381,16 +398,19 @@ void CodeGenModule::checkAliases() {
381398
for (const GlobalDecl &GD : Aliases) {
382399
const auto *D = cast<ValueDecl>(GD.getDecl());
383400
SourceLocation Location;
401+
SourceRange Range;
384402
bool IsIFunc = D->hasAttr<IFuncAttr>();
385-
if (const Attr *A = D->getDefiningAttr())
403+
if (const Attr *A = D->getDefiningAttr()) {
386404
Location = A->getLocation();
387-
else
405+
Range = A->getRange();
406+
} else
388407
llvm_unreachable("Not an alias or ifunc?");
389408

390409
StringRef MangledName = getMangledName(GD);
391410
llvm::GlobalValue *Alias = GetGlobalValue(MangledName);
392411
const llvm::GlobalValue *GV = nullptr;
393-
if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV)) {
412+
if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV,
413+
MangledDeclNames, Range)) {
394414
Error = true;
395415
continue;
396416
}

clang/test/CodeGen/alias.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux -verify -emit-llvm-only %s
2+
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
3+
4+
void *f1_ifunc(void) { return nullptr; }
5+
void f1(void) __attribute__((alias("f1_ifunc")));
6+
// expected-error@-1 {{alias must point to a defined variable or function}}
7+
// expected-note@-2 {{must refer to its mangled name}}
8+
// expected-note@-3 {{function by that name is mangled as}}
9+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:47}:"alias(\"_Z8f1_ifuncv\")"
10+
11+
void *f6_resolver_resolver(void) { return 0; }
12+
void *f6_resolver(void) __attribute__((alias("f6_resolver_resolver")));
13+
// expected-error@-1 {{alias must point to a defined variable or function}}
14+
// expected-note@-2 {{must refer to its mangled name}}
15+
// expected-note@-3 {{function by that name is mangled as}}
16+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:40-[[@LINE-4]]:69}:"alias(\"_Z20f6_resolver_resolverv\")"
17+
void f6(void) __attribute__((alias("f6_resolver")));
18+
// expected-error@-1 {{alias must point to a defined variable or function}}
19+
// expected-note@-2 {{must refer to its mangled name}}
20+
// expected-note@-3 {{function by that name is mangled as}}
21+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:50}:"alias(\"_Z11f6_resolverv\")"
22+
23+
__attribute__((unused, alias("resolver"), deprecated("hahahaha, isn't C great?")))
24+
void func();
25+
// expected-error@-2 {{alias must point to a defined variable or function}}
26+
// expected-note@-3 {{must refer to its mangled name}}
27+

clang/test/CodeGen/attr-ifunc.c

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ void bar(void) __attribute__((ifunc("foo")));
1212
void *f1_ifunc(void);
1313
void f1(void) __attribute__((ifunc("f1_ifunc")));
1414
// expected-error@-1 {{ifunc must point to a defined function}}
15+
// expected-note@-2 {{must refer to its mangled name}}
1516

1617
void *f2_a(void) __attribute__((alias("f2_b")));
1718
void *f2_b(void) __attribute__((ifunc("f2_a")));

clang/test/CodeGen/attr-ifunc.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s
2+
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
3+
4+
void *f1_ifunc(void) { return nullptr; }
5+
void f1(void) __attribute__((ifunc("f1_ifunc")));
6+
// expected-error@-1 {{ifunc must point to a defined function}}
7+
// expected-note@-2 {{must refer to its mangled name}}
8+
// expected-note@-3 {{function by that name is mangled as}}
9+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:47}:"ifunc(\"_Z8f1_ifuncv\")"
10+
11+
void *f6_resolver_resolver(void) { return 0; }
12+
void *f6_resolver(void) __attribute__((ifunc("f6_resolver_resolver")));
13+
// expected-error@-1 {{ifunc must point to a defined function}}
14+
// expected-note@-2 {{must refer to its mangled name}}
15+
// expected-note@-3 {{function by that name is mangled as}}
16+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:40-[[@LINE-4]]:69}:"ifunc(\"_Z20f6_resolver_resolverv\")"
17+
void f6(void) __attribute__((ifunc("f6_resolver")));
18+
// expected-error@-1 {{ifunc must point to a defined function}}
19+
// expected-note@-2 {{must refer to its mangled name}}
20+
// expected-note@-3 {{function by that name is mangled as}}
21+
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:30-[[@LINE-4]]:50}:"ifunc(\"_Z11f6_resolverv\")"
22+
23+
__attribute__((unused, ifunc("resolver"), deprecated("hahahaha, isn't C great?")))
24+
void func();
25+
// expected-error@-2 {{ifunc must point to a defined function}}
26+
// expected-note@-3 {{must refer to its mangled name}}
27+

clang/test/Sema/attr-alias-elf.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ void g1(void) {
55
}
66

77
void f2(void) __attribute__((alias("g2"))); // expected-error {{alias must point to a defined variable or function}}
8-
8+
// expected-note@-1 {{must refer to its mangled name}}
99

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

1314

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

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

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

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

5660
void test2_bar() {}

clang/test/SemaCXX/externc-ifunc-resolver.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-linux-gnu -verify %s
2+
// RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
23

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

0 commit comments

Comments
 (0)