Skip to content

Commit 2ac562a

Browse files
authored
[Sema] Mark alias/ifunc targets used and consider mangled names
https://reviews.llvm.org/D54188 marked "alias" targets as used in C to fix -Wunused false positives. This patch extends the approach to handle mangled names to support global scope names in C++ and the `overloadable` attribute in C. In addition, we mark ifunc targets as used to fix #63957. While our approach has false negatives for namespace scope names, the majority of alias/ifunc C++ uses (global scope with no overloads) are handled. Note: The following function with internal linkage but C language linkage type is mangled in Clang but not in GCC. This inconsistency makes alias/ifunc difficult to use in C++ with portability (#88593). ``` extern "C" { static void f0() {} // GCC: void g0() __attribute__((alias("_ZL2f0v"))); // Clang: void g0() __attribute__((alias("f0"))); } ``` Pull Request: #87130
1 parent 694c444 commit 2ac562a

File tree

6 files changed

+46
-19
lines changed

6 files changed

+46
-19
lines changed

clang/lib/Sema/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(LLVM_LINK_COMPONENTS
22
Core
3+
Demangle
34
FrontendHLSL
45
FrontendOpenMP
56
MC

clang/lib/Sema/SemaDeclAttr.cpp

+33-11
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "llvm/ADT/STLExtras.h"
4646
#include "llvm/ADT/STLForwardCompat.h"
4747
#include "llvm/ADT/StringExtras.h"
48+
#include "llvm/Demangle/Demangle.h"
4849
#include "llvm/IR/Assumptions.h"
4950
#include "llvm/MC/MCSectionMachO.h"
5051
#include "llvm/Support/Error.h"
@@ -1983,6 +1984,36 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
19831984
D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
19841985
}
19851986

1987+
// Mark alias/ifunc target as used. Due to name mangling, we look up the
1988+
// demangled name ignoring parameters (not supported by microsoftDemangle
1989+
// https://github.com/llvm/llvm-project/issues/88825). This should handle the
1990+
// majority of use cases while leaving namespace scope names unmarked.
1991+
static void markUsedForAliasOrIfunc(Sema &S, Decl *D, const ParsedAttr &AL,
1992+
StringRef Str) {
1993+
std::unique_ptr<char, llvm::FreeDeleter> Demangled;
1994+
if (S.getASTContext().getCXXABIKind() != TargetCXXABI::Microsoft)
1995+
Demangled.reset(llvm::itaniumDemangle(Str, /*ParseParams=*/false));
1996+
std::unique_ptr<MangleContext> MC(S.Context.createMangleContext());
1997+
SmallString<256> Name;
1998+
1999+
const DeclarationNameInfo Target(
2000+
&S.Context.Idents.get(Demangled ? Demangled.get() : Str), AL.getLoc());
2001+
LookupResult LR(S, Target, Sema::LookupOrdinaryName);
2002+
if (S.LookupName(LR, S.TUScope)) {
2003+
for (NamedDecl *ND : LR) {
2004+
if (MC->shouldMangleDeclName(ND)) {
2005+
llvm::raw_svector_ostream Out(Name);
2006+
Name.clear();
2007+
MC->mangleName(GlobalDecl(ND), Out);
2008+
} else {
2009+
Name = ND->getIdentifier()->getName();
2010+
}
2011+
if (Name == Str)
2012+
ND->markUsed(S.Context);
2013+
}
2014+
}
2015+
}
2016+
19862017
static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
19872018
StringRef Str;
19882019
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
@@ -1995,6 +2026,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
19952026
return;
19962027
}
19972028

2029+
markUsedForAliasOrIfunc(S, D, AL, Str);
19982030
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
19992031
}
20002032

@@ -2029,17 +2061,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
20292061
}
20302062
}
20312063

2032-
// Mark target used to prevent unneeded-internal-declaration warnings.
2033-
if (!S.LangOpts.CPlusPlus) {
2034-
// FIXME: demangle Str for C++, as the attribute refers to the mangled
2035-
// linkage name, not the pre-mangled identifier.
2036-
const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
2037-
LookupResult LR(S, target, Sema::LookupOrdinaryName);
2038-
if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
2039-
for (NamedDecl *ND : LR)
2040-
ND->markUsed(S.Context);
2041-
}
2042-
2064+
markUsedForAliasOrIfunc(S, D, AL, Str);
20432065
D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
20442066
}
20452067

clang/test/AST/ast-dump-attr-json.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ __thread __attribute__ ((tls_model ("local-exec"))) int tls_model_var;
4646
// CHECK-NEXT: "tokLen": 11
4747
// CHECK-NEXT: }
4848
// CHECK-NEXT: },
49+
// CHECK-NEXT: "isUsed": true,
4950
// CHECK-NEXT: "name": "global_decl",
5051
// CHECK-NEXT: "mangledName": "global_decl",
5152
// CHECK-NEXT: "type": {

clang/test/Sema/alias-unused-win.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extern "C" {
77
static int f(void) { return 42; } // cxx-warning{{unused function 'f'}}
88
int g(void) __attribute__((alias("f")));
99

10-
static int foo [] = { 42, 0xDEAD }; // cxx-warning{{variable 'foo' is not needed and will not be emitted}}
10+
static int foo [] = { 42, 0xDEAD };
1111
extern typeof(foo) bar __attribute__((unused, alias("foo")));
1212

1313
static int __attribute__((overloadable)) f0(int x) { return x; } // expected-warning{{unused function 'f0'}}

clang/test/Sema/alias-unused.cpp

+9-7
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,26 @@ extern typeof(foo) bar __attribute__((unused, alias("foo")));
1414
/// We report a warning in C++ mode because the internal linkage `resolver` gets
1515
/// mangled as it does not have a language linkage. GCC does not mangle
1616
/// `resolver` or report a warning.
17-
static int (*resolver(void))(void) { return f; } // expected-warning{{unused function 'resolver'}}
17+
static int (*resolver(void))(void) { return f; } // cxx-warning{{unused function 'resolver'}}
1818
int ifunc(void) __attribute__((ifunc("resolver")));
1919

20-
static int __attribute__((overloadable)) f0(int x) { return x; } // expected-warning{{unused function 'f0'}}
20+
static int __attribute__((overloadable)) f0(int x) { return x; }
2121
static float __attribute__((overloadable)) f0(float x) { return x; } // expected-warning{{unused function 'f0'}}
2222
int g0(void) __attribute__((alias("_ZL2f0i")));
2323

2424
#ifdef __cplusplus
25-
static int f1() { return 42; } // expected-warning{{unused function 'f1'}}
25+
static int f1() { return 42; }
2626
int g1(void) __attribute__((alias("_ZL2f1v")));
2727
}
2828

29-
static int f2(int) { return 42; } // expected-warning{{unused function 'f2'}}
30-
static int f2() { return 42; } // expected-warning{{unused function 'f2'}}
29+
/// We demangle alias/ifunc target and mark all found functions as used.
30+
31+
static int f2(int) { return 42; } // cxx-warning{{unused function 'f2'}}
32+
static int f2() { return 42; }
3133
int g2() __attribute__((alias("_ZL2f2v")));
3234

33-
static int (*resolver1())() { return f; } // expected-warning{{unused function 'resolver1'}}
34-
static int (*resolver1(int))() { return f; } // expected-warning{{unused function 'resolver1'}}
35+
static int (*resolver1())() { return f; } // cxx-warning{{unused function 'resolver1'}}
36+
static int (*resolver1(int))() { return f; }
3537
int ifunc1() __attribute__((ifunc("_ZL9resolver1i")));
3638

3739
/// TODO: We should report "unused function" for f3(int).

utils/bazel/llvm-project-overlay/clang/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,7 @@ cc_library(
11361136
"//llvm:AllTargetsAsmParsers",
11371137
"//llvm:AllTargetsCodeGens",
11381138
"//llvm:Core",
1139+
"//llvm:Demangle",
11391140
"//llvm:FrontendHLSL",
11401141
"//llvm:FrontendOpenMP",
11411142
"//llvm:MC",

0 commit comments

Comments
 (0)