Skip to content

Commit 2f98a9d

Browse files
committed
Make changes to CodeGen and Serialization that are needed to support
feature-based availability rdar://137999979
1 parent cf6606e commit 2f98a9d

File tree

7 files changed

+326
-1
lines changed

7 files changed

+326
-1
lines changed

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,13 @@ class ScalarExprEmitter
552552
}
553553

554554
Value *VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
555+
if (E->hasDomainName()) {
556+
auto DomainName = E->getDomainName();
557+
ASTContext::AvailabilityDomainInfo Info =
558+
CGF.getContext().getFeatureAvailInfo(DomainName);
559+
return CGF.EmitScalarExpr(Info.Call);
560+
}
561+
555562
VersionTuple Version = E->getVersionAsWritten();
556563

557564
// If we're checking for a platform older than our minimum deployment

clang/lib/CodeGen/CGObjCMac.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3197,6 +3197,8 @@ PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
31973197
const ObjCProtocolDecl *Proto,
31983198
bool IsClassProperty) {
31993199
for (const auto *PD : Proto->properties()) {
3200+
if (Proto->getASTContext().hasUnavailableFeature(PD))
3201+
continue;
32003202
if (IsClassProperty != PD->isClassProperty())
32013203
continue;
32023204
if (!PropertySet.insert(PD->getIdentifier()).second)
@@ -3240,6 +3242,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
32403242
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
32413243
for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
32423244
for (auto *PD : ClassExt->properties()) {
3245+
if (CGM.getContext().hasUnavailableFeature(PD))
3246+
continue;
32433247
if (IsClassProperty != PD->isClassProperty())
32443248
continue;
32453249
if (PD->isDirectProperty())
@@ -3249,6 +3253,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
32493253
}
32503254

32513255
for (const auto *PD : OCD->properties()) {
3256+
if (CGM.getContext().hasUnavailableFeature(PD))
3257+
continue;
32523258
if (IsClassProperty != PD->isClassProperty())
32533259
continue;
32543260
// Don't emit duplicate metadata for properties that were already in a
@@ -6735,6 +6741,9 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
67356741
void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
67366742
const ObjCMethodDecl *MD,
67376743
bool forProtocol) {
6744+
if (CGM.getContext().hasUnavailableFeature(MD))
6745+
return;
6746+
67386747
auto method = builder.beginStruct(ObjCTypes.MethodTy);
67396748
method.add(GetMethodVarName(MD->getSelector()));
67406749
method.add(GetMethodVarType(MD));
@@ -6934,6 +6943,9 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
69346943
if (!IVD->getDeclName())
69356944
continue;
69366945

6946+
if (CGM.getContext().hasUnavailableFeature(IVD))
6947+
continue;
6948+
69376949
auto ivar = ivars.beginStruct(ObjCTypes.IvarnfABITy);
69386950
ivar.add(EmitIvarOffsetVar(ID->getClassInterface(), IVD,
69396951
ComputeIvarBaseOffset(CGM, ID, IVD)));

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5222,6 +5222,9 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
52225222
return;
52235223
}
52245224

5225+
if (Context.hasUnavailableFeature(D))
5226+
return;
5227+
52255228
// The tentative definition is the only definition.
52265229
EmitGlobalVarDefinition(D);
52275230
}
@@ -6729,6 +6732,9 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
67296732
void CodeGenModule::EmitObjCPropertyImplementations(const
67306733
ObjCImplementationDecl *D) {
67316734
for (const auto *PID : D->property_impls()) {
6735+
if (Context.hasUnavailableFeature(PID->getPropertyDecl()))
6736+
continue;
6737+
67326738
// Dynamic is just for type-checking.
67336739
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
67346740
ObjCPropertyDecl *PD = PID->getPropertyDecl();
@@ -6887,6 +6893,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
68876893
if (auto *FD = dyn_cast<FunctionDecl>(D); FD && FD->isImmediateFunction())
68886894
return;
68896895

6896+
if (Context.hasUnavailableFeature(D))
6897+
return;
6898+
68906899
switch (D->getKind()) {
68916900
case Decl::CXXConversion:
68926901
case Decl::CXXMethod:
@@ -7016,6 +7025,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
70167025
}
70177026
case Decl::ObjCMethod: {
70187027
auto *OMD = cast<ObjCMethodDecl>(D);
7028+
if (Context.hasUnavailableFeature(OMD->getClassInterface()))
7029+
break;
70197030
// If this is not a prototype, emit the body.
70207031
if (OMD->getBody())
70217032
CodeGenFunction(*this).GenerateObjCMethod(OMD);

clang/lib/Serialization/ASTReaderStmt.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1659,11 +1659,18 @@ void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
16591659

16601660
void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
16611661
VisitExpr(E);
1662+
unsigned DomainNameLength = Record.readInt();
1663+
E->setHasDomainName(Record.readInt());
16621664
SourceRange R = Record.readSourceRange();
16631665
E->AtLoc = R.getBegin();
16641666
E->RParen = R.getEnd();
16651667
E->VersionToCheck.Version = Record.readVersionTuple();
16661668
E->VersionToCheck.SourceVersion = Record.readVersionTuple();
1669+
if (E->hasDomainName()) {
1670+
std::string DomainName = Record.readString();
1671+
assert(DomainNameLength == DomainName.size());
1672+
strcpy(E->getTrailingObjects<char>(), DomainName.data());
1673+
}
16671674
}
16681675

16691676
//===----------------------------------------------------------------------===//
@@ -3481,7 +3488,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
34813488
break;
34823489

34833490
case EXPR_OBJC_AVAILABILITY_CHECK:
3484-
S = new (Context) ObjCAvailabilityCheckExpr(Empty);
3491+
S = ObjCAvailabilityCheckExpr::CreateEmpty(
3492+
Context, Empty, Record[ASTStmtReader::NumExprFields]);
34853493
break;
34863494

34873495
case STMT_SEH_LEAVE:

clang/lib/Serialization/ASTWriterStmt.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,9 +1623,13 @@ void ASTStmtWriter::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
16231623

16241624
void ASTStmtWriter::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
16251625
VisitExpr(E);
1626+
Record.push_back(E->hasDomainName() ? E->getDomainName().size() : 0);
1627+
Record.push_back(E->hasDomainName());
16261628
Record.AddSourceRange(E->getSourceRange());
16271629
Record.AddVersionTuple(E->getVersion());
16281630
Record.AddVersionTuple(E->getVersionAsWritten());
1631+
if (E->hasDomainName())
1632+
Record.AddString(E->getDomainName());
16291633
Code = serialization::EXPR_OBJC_AVAILABILITY_CHECK;
16301634
}
16311635

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck --check-prefixes=CHECK,DOMAIN %s
3+
4+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-pch -o %t %s
5+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -include-pch %t -emit-llvm -o - %s | FileCheck %s
6+
7+
// CHECK: %[[STRUCT_S0:.*]] = type { i32 }
8+
// CHECK: @g0 = external global i32, align 4
9+
// CHECK-NOT: @g1
10+
// CHECK-NOT: @g2
11+
12+
#ifndef HEADER
13+
#define HEADER
14+
15+
#include <feature-availability.h>
16+
17+
#define AVAIL 0
18+
19+
#ifdef USE_DOMAIN
20+
// DOMAIN: @g3 = extern_weak global i32, align 4
21+
22+
static struct __AvailabilityDomain feature1 __attribute__((availability_domain(feature1))) = {__AVAILABILITY_DOMAIN_ENABLED, 0};
23+
static struct __AvailabilityDomain feature2 __attribute__((availability_domain(feature2))) = {__AVAILABILITY_DOMAIN_DISABLED, 0};
24+
#endif
25+
26+
__attribute__((availability(domain:feature1, AVAIL))) int func0(void);
27+
__attribute__((availability(domain:feature2, AVAIL))) int func1(void);
28+
int func2(void);
29+
30+
__attribute__((availability(domain:feature1, AVAIL))) extern int g0;
31+
__attribute__((availability(domain:feature2, AVAIL))) int g1 = 100;
32+
__attribute__((availability(domain:feature2, AVAIL))) int g2;
33+
34+
struct __attribute__((availability(domain:feature1, AVAIL))) S0 {
35+
int d0;
36+
};
37+
38+
// CHECK-LABEL: define void @test0()
39+
// CHECK-NOT: br
40+
// CHECK: call i32 @func0()
41+
// CHECK: store i32 123, ptr @g0, align 4
42+
// CHECK-NOT: func1()
43+
// CHECK-NOT: func2()
44+
void test0(void) {
45+
if (__builtin_available(domain:feature1)) {
46+
func0();
47+
g0 = 123;
48+
}
49+
50+
if (__builtin_available(domain:feature2)) {
51+
func1();
52+
g1 = 123;
53+
}
54+
55+
if (__builtin_available(domain:feature1))
56+
if (__builtin_available(domain:feature2)) {
57+
func2();
58+
}
59+
}
60+
61+
// CHECK-LABEL: define void @test1()
62+
__attribute__((availability(domain:feature1, AVAIL)))
63+
void test1(void) {
64+
}
65+
66+
// CHECK-NOT: @test2(
67+
__attribute__((availability(domain:feature2, AVAIL)))
68+
void test2(void) {
69+
}
70+
71+
// CHECK-LABEL: define void @test3(
72+
// CHECK: %[[D0:.*]] = getelementptr inbounds %[[STRUCT_S0]], ptr %{{.*}}, i32 0, i32 0
73+
// CHECK: store i32 134, ptr %[[D0]], align 4
74+
__attribute__((availability(domain:feature1, AVAIL)))
75+
void test3(struct S0 *s0) {
76+
s0->d0 = 134;
77+
}
78+
79+
#ifdef USE_DOMAIN
80+
// DOMAIN-LABEL: define void @test4()
81+
// DOMAIN: %[[CALL:.*]] = call i32 @pred1()
82+
// DOMAIN-NEXT: %[[TOBOOL:.*]] = icmp ne i32 %[[CALL]], 0
83+
// DOMAIN-NEXT: br i1 %[[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
84+
//
85+
// DOMAIN: [[IF_THEN]]:
86+
// DOMAIN-NEXT: %[[CALL1:.*]] = call i32 @func3()
87+
// DOMAIN-NEXT: store i32 1, ptr @g3, align 4
88+
// DOMAIN-NEXT: br label %[[IF_END]]
89+
//
90+
// DOMAIN: [[IF_END]]:
91+
// DOMAIN-NEXT: ret void
92+
93+
int pred1(void);
94+
static struct __AvailabilityDomain feature3 __attribute__((availability_domain(feature3))) = {__AVAILABILITY_DOMAIN_DYNAMIC, pred1};
95+
__attribute__((availability(domain:feature3, AVAIL))) int func3(void);
96+
__attribute__((availability(domain:feature3, AVAIL))) extern int g3;
97+
98+
void test4(void) {
99+
if (__builtin_available(domain:feature3)) {
100+
func3();
101+
g3 = 1;
102+
}
103+
}
104+
105+
// DOMAIN: declare extern_weak i32 @func3()
106+
107+
#endif
108+
109+
#endif /* HEADER */

0 commit comments

Comments
 (0)