Skip to content

Commit 50ae8a2

Browse files
authored
[InstallAPI] Collect global functions (#83952)
* Include whether functions are inlinable as they impact whether to add them into the tbd file and for future verification. * Fix how clang arguments got passed along, previously spacing was passed along to CC1 causing search path inputs to look non-existent.
1 parent a9b0d75 commit 50ae8a2

File tree

10 files changed

+182
-11
lines changed

10 files changed

+182
-11
lines changed

clang/include/clang/InstallAPI/Frontend.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
5050
/// \param D The pointer to the declaration from traversing AST.
5151
/// \param Access The intended access level of symbol.
5252
/// \param Flags The flags that describe attributes of the symbol.
53+
/// \param Inlined Whether declaration is inlined, only applicable to
54+
/// functions.
5355
/// \return The non-owning pointer to added record in slice.
5456
GlobalRecord *addGlobal(StringRef Name, RecordLinkage Linkage,
5557
GlobalRecord::Kind GV,
5658
const clang::AvailabilityInfo Avail, const Decl *D,
5759
const HeaderType Access,
58-
SymbolFlags Flags = SymbolFlags::None);
60+
SymbolFlags Flags = SymbolFlags::None,
61+
bool Inlined = false);
5962

6063
/// Add ObjC Class record with attributes from AST.
6164
///

clang/include/clang/InstallAPI/Visitor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class InstallAPIVisitor final : public ASTConsumer,
3737
/// Collect global variables.
3838
bool VisitVarDecl(const VarDecl *D);
3939

40+
/// Collect global functions.
41+
bool VisitFunctionDecl(const FunctionDecl *D);
42+
4043
/// Collect Objective-C Interface declarations.
4144
/// Every Objective-C class has an interface declaration that lists all the
4245
/// ivars, properties, and methods of the class.

clang/lib/InstallAPI/Frontend.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ namespace clang::installapi {
1919
GlobalRecord *FrontendRecordsSlice::addGlobal(
2020
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
2121
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
22-
SymbolFlags Flags) {
22+
SymbolFlags Flags, bool Inlined) {
2323

24-
auto *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags);
24+
auto *GR =
25+
llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);
2526
FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
2627
return GR;
2728
}

clang/lib/InstallAPI/Visitor.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "clang/InstallAPI/Visitor.h"
10+
#include "clang/AST/ParentMapContext.h"
1011
#include "clang/Basic/Linkage.h"
1112
#include "clang/InstallAPI/Frontend.h"
1213
#include "llvm/ADT/SmallString.h"
@@ -27,6 +28,31 @@ static bool isExported(const NamedDecl *D) {
2728
(LV.getVisibility() == DefaultVisibility);
2829
}
2930

31+
static bool isInlined(const FunctionDecl *D) {
32+
bool HasInlineAttribute = false;
33+
bool NoCXXAttr =
34+
(!D->getASTContext().getLangOpts().CPlusPlus &&
35+
!D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&
36+
!D->hasAttr<DLLExportAttr>());
37+
38+
// Check all redeclarations to find an inline attribute or keyword.
39+
for (const auto *RD : D->redecls()) {
40+
if (!RD->isInlined())
41+
continue;
42+
HasInlineAttribute = true;
43+
if (!(NoCXXAttr || RD->hasAttr<GNUInlineAttr>()))
44+
continue;
45+
if (RD->doesThisDeclarationHaveABody() &&
46+
RD->isInlineDefinitionExternallyVisible())
47+
return false;
48+
}
49+
50+
if (!HasInlineAttribute)
51+
return false;
52+
53+
return true;
54+
}
55+
3056
static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal) {
3157
SymbolFlags Result = SymbolFlags::None;
3258
if (WeakDef)
@@ -204,4 +230,56 @@ bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
204230
return true;
205231
}
206232

233+
bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
234+
if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) {
235+
// Skip member function in class templates.
236+
if (M->getParent()->getDescribedClassTemplate() != nullptr)
237+
return true;
238+
239+
// Skip methods in CXX RecordDecls.
240+
for (auto P : D->getASTContext().getParents(*M)) {
241+
if (P.get<CXXRecordDecl>())
242+
return true;
243+
}
244+
245+
// Skip CXX ConstructorDecls and DestructorDecls.
246+
if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M))
247+
return true;
248+
}
249+
250+
// Skip templated functions.
251+
switch (D->getTemplatedKind()) {
252+
case FunctionDecl::TK_NonTemplate:
253+
case FunctionDecl::TK_DependentNonTemplate:
254+
break;
255+
case FunctionDecl::TK_MemberSpecialization:
256+
case FunctionDecl::TK_FunctionTemplateSpecialization:
257+
if (auto *TempInfo = D->getTemplateSpecializationInfo()) {
258+
if (!TempInfo->isExplicitInstantiationOrSpecialization())
259+
return true;
260+
}
261+
break;
262+
case FunctionDecl::TK_FunctionTemplate:
263+
case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
264+
return true;
265+
}
266+
267+
auto Access = getAccessForDecl(D);
268+
if (!Access)
269+
return true;
270+
auto Name = getMangledName(D);
271+
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
272+
const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==
273+
TSK_ExplicitInstantiationDeclaration;
274+
const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>();
275+
const bool Inlined = isInlined(D);
276+
const RecordLinkage Linkage = (Inlined || !isExported(D))
277+
? RecordLinkage::Internal
278+
: RecordLinkage::Exported;
279+
Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, D,
280+
*Access, getFlags(WeakDef, /*ThreadLocal=*/false),
281+
Inlined);
282+
return true;
283+
}
284+
207285
} // namespace clang::installapi

clang/test/InstallAPI/functions.test

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
4+
5+
// RUN: clang-installapi -target arm64-apple-macos13.1 \
6+
// RUN: -I%t/usr/include -I%t/usr/local/include \
7+
// RUN: -install_name @rpath/lib/libfunctions.dylib \
8+
// RUN: %t/inputs.json -o %t/outputs.tbd 2>&1 | FileCheck %s --allow-empty
9+
// RUN: llvm-readtapi -compare %t/outputs.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty
10+
11+
// CHECK-NOT: error:
12+
// CHECK-NOT: warning:
13+
14+
//--- usr/include/functions.h
15+
inline int inlined_func(void) { return 1;}
16+
int public(int a);
17+
18+
//--- usr/local/include/private_functions.h
19+
__attribute__((visibility("hidden")))
20+
void hidden(void);
21+
22+
//--- inputs.json.in
23+
{
24+
"headers": [ {
25+
"path" : "DSTROOT/usr/include/functions.h",
26+
"type" : "public"
27+
},
28+
{
29+
"path" : "DSTROOT/usr/local/include/private_functions.h",
30+
"type" : "private"
31+
}
32+
],
33+
"version": "3"
34+
}
35+
36+
//--- expected.tbd
37+
{
38+
"main_library": {
39+
"compatibility_versions": [
40+
{
41+
"version": "0"
42+
}
43+
],
44+
"current_versions": [
45+
{
46+
"version": "0"
47+
}
48+
],
49+
"exported_symbols": [
50+
{
51+
"text": {
52+
"global": [
53+
"_public"
54+
]
55+
}
56+
}
57+
],
58+
"flags": [
59+
{
60+
"attributes": [
61+
"not_app_extension_safe"
62+
]
63+
}
64+
],
65+
"install_names": [
66+
{
67+
"name": "@rpath/lib/libfunctions.dylib"
68+
}
69+
],
70+
"target_info": [
71+
{
72+
"min_deployment": "13.1",
73+
"target": "arm64-macos"
74+
}
75+
]
76+
},
77+
"tapi_tbd_version": 5
78+
}

clang/tools/clang-installapi/Options.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
112112
for (const Arg *A : ArgList) {
113113
if (A->isClaimed())
114114
continue;
115-
FrontendArgs.emplace_back(A->getAsString(ArgList));
115+
116+
FrontendArgs.emplace_back(A->getSpelling());
117+
llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
116118
}
117119
FrontendArgs.push_back("-fsyntax-only");
118120
}

llvm/include/llvm/TextAPI/Record.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,20 @@ class GlobalRecord : public Record {
103103
};
104104

105105
GlobalRecord(StringRef Name, RecordLinkage Linkage, SymbolFlags Flags,
106-
Kind GV)
107-
: Record({Name, Linkage, Flags}), GV(GV) {}
106+
Kind GV, bool Inlined)
107+
: Record({Name, Linkage, Flags}), GV(GV), Inlined(Inlined) {}
108108

109109
bool isFunction() const { return GV == Kind::Function; }
110110
bool isVariable() const { return GV == Kind::Variable; }
111111
void setKind(const Kind &V) {
112112
if (GV == Kind::Unknown)
113113
GV = V;
114114
}
115+
bool isInlined() const { return Inlined; }
115116

116117
private:
117118
Kind GV;
119+
bool Inlined = false;
118120
};
119121

120122
// Define Objective-C instance variable records.

llvm/include/llvm/TextAPI/RecordsSlice.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@ class RecordsSlice {
5353
/// \param Linkage The linkage of symbol.
5454
/// \param GV The kind of global.
5555
/// \param Flags The flags that describe attributes of the symbol.
56+
/// \param Inlined Whether declaration is inlined, only applicable to
57+
/// functions.
5658
/// \return The non-owning pointer to added record in slice.
5759
GlobalRecord *addGlobal(StringRef Name, RecordLinkage Linkage,
5860
GlobalRecord::Kind GV,
59-
SymbolFlags Flags = SymbolFlags::None);
61+
SymbolFlags Flags = SymbolFlags::None,
62+
bool Inlined = false);
6063

6164
/// Add ObjC Class record.
6265
///

llvm/lib/TextAPI/RecordsSlice.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName,
171171
}
172172

173173
GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
174-
GlobalRecord::Kind GV,
175-
SymbolFlags Flags) {
174+
GlobalRecord::Kind GV, SymbolFlags Flags,
175+
bool Inlined) {
176176
if (GV == GlobalRecord::Kind::Function)
177177
Flags |= SymbolFlags::Text;
178178
else if (GV == GlobalRecord::Kind::Variable)
@@ -182,7 +182,7 @@ GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
182182
auto Result = Globals.insert({Name, nullptr});
183183
if (Result.second)
184184
Result.first->second =
185-
std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV);
185+
std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV, Inlined);
186186
else {
187187
updateLinkage(Result.first->second.get(), Linkage);
188188
updateFlags(Result.first->second.get(), Flags);

llvm/unittests/TextAPI/RecordTests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ TEST(TAPIRecord, Simple) {
1919
GlobalRecord API{"_sym", RecordLinkage::Rexported,
2020
SymbolFlags::Rexported | SymbolFlags::Text |
2121
SymbolFlags::ThreadLocalValue,
22-
GlobalRecord::Kind::Function};
22+
GlobalRecord::Kind::Function, /*Inlined=*/false};
2323
EXPECT_TRUE(API.isExported());
2424
EXPECT_TRUE(API.isText());
2525
EXPECT_TRUE(API.isRexported());
@@ -30,6 +30,7 @@ TEST(TAPIRecord, Simple) {
3030
EXPECT_FALSE(API.isWeakDefined());
3131
EXPECT_FALSE(API.isWeakReferenced());
3232
EXPECT_FALSE(API.isVariable());
33+
EXPECT_FALSE(API.isInlined());
3334
}
3435

3536
TEST(TAPIRecord, SimpleObjC) {

0 commit comments

Comments
 (0)