Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sema] Mark alias/ifunc targets used and consider mangled names #87130

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
Core
Demangle
FrontendHLSL
FrontendOpenMP
MC
Expand Down
44 changes: 33 additions & 11 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/Error.h"
Expand Down Expand Up @@ -1982,6 +1983,36 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
}

// Mark alias/ifunc target as used. Due to name mangling, we look up the
// demangled name ignoring parameters (not supported by microsoftDemangle). This
// should handle the majority of use cases while leaving namespace scope names
// unmarked.
static void markUsedForAliasOrIfunc(Sema &S, Decl *D, const ParsedAttr &AL,
StringRef Str) {
std::unique_ptr<char, llvm::FreeDeleter> Demangled;
if (S.getASTContext().getCXXABIKind() != TargetCXXABI::Microsoft)
Demangled.reset(llvm::itaniumDemangle(Str, /*ParseParams=*/false));
std::unique_ptr<MangleContext> MC(S.Context.createMangleContext());
SmallString<256> Name;

const DeclarationNameInfo Target(
&S.Context.Idents.get(Demangled ? Demangled.get() : Str), AL.getLoc());
LookupResult LR(S, Target, Sema::LookupOrdinaryName);
if (S.LookupName(LR, S.TUScope)) {
for (NamedDecl *ND : LR) {
if (MC->shouldMangleDeclName(ND)) {
llvm::raw_svector_ostream Out(Name);
Name.clear();
MC->mangleName(GlobalDecl(ND), Out);
} else {
Name = ND->getIdentifier()->getName();
MaskRay marked this conversation as resolved.
Show resolved Hide resolved
}
if (Name == Str)
ND->markUsed(S.Context);
}
}
}

static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
Expand All @@ -1994,6 +2025,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}

markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}

Expand Down Expand Up @@ -2028,17 +2060,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

// Mark target used to prevent unneeded-internal-declaration warnings.
if (!S.LangOpts.CPlusPlus) {
// FIXME: demangle Str for C++, as the attribute refers to the mangled
// linkage name, not the pre-mangled identifier.
const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
LookupResult LR(S, target, Sema::LookupOrdinaryName);
if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
for (NamedDecl *ND : LR)
ND->markUsed(S.Context);
}

markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
}

Expand Down
1 change: 1 addition & 0 deletions clang/test/AST/ast-dump-attr-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ __thread __attribute__ ((tls_model ("local-exec"))) int tls_model_var;
// CHECK-NEXT: "tokLen": 11
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "isUsed": true,
// CHECK-NEXT: "name": "global_decl",
// CHECK-NEXT: "mangledName": "global_decl",
// CHECK-NEXT: "type": {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Sema/alias-unused-win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extern "C" {
static int f(void) { return 42; } // cxx-warning{{unused function 'f'}}
int g(void) __attribute__((alias("f")));

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

static int __attribute__((overloadable)) f0(int x) { return x; } // expected-warning{{unused function 'f0'}}
Expand Down
16 changes: 9 additions & 7 deletions clang/test/Sema/alias-unused.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,26 @@ extern typeof(foo) bar __attribute__((unused, alias("foo")));
/// We report a warning in C++ mode because the internal linkage `resolver` gets
/// mangled as it does not have a language linkage. GCC does not mangle
/// `resolver` or report a warning.
static int (*resolver(void))(void) { return f; } // expected-warning{{unused function 'resolver'}}
static int (*resolver(void))(void) { return f; } // cxx-warning{{unused function 'resolver'}}
nickdesaulniers marked this conversation as resolved.
Show resolved Hide resolved
int ifunc(void) __attribute__((ifunc("resolver")));

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

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

static int f2(int) { return 42; } // expected-warning{{unused function 'f2'}}
static int f2() { return 42; } // expected-warning{{unused function 'f2'}}
/// We demangle alias/ifunc target and mark all found functions as used.

static int f2(int) { return 42; } // cxx-warning{{unused function 'f2'}}
static int f2() { return 42; }
int g2() __attribute__((alias("_ZL2f2v")));

static int (*resolver1())() { return f; } // expected-warning{{unused function 'resolver1'}}
static int (*resolver1(int))() { return f; } // expected-warning{{unused function 'resolver1'}}
static int (*resolver1())() { return f; } // cxx-warning{{unused function 'resolver1'}}
static int (*resolver1(int))() { return f; }
int ifunc1() __attribute__((ifunc("_ZL9resolver1i")));

/// TODO: We should report "unused function" for f3(int).
Expand Down
1 change: 1 addition & 0 deletions utils/bazel/llvm-project-overlay/clang/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ cc_library(
"//llvm:AllTargetsAsmParsers",
"//llvm:AllTargetsCodeGens",
"//llvm:Core",
"//llvm:Demangle",
"//llvm:FrontendHLSL",
"//llvm:FrontendOpenMP",
"//llvm:MC",
Expand Down
Loading