Skip to content

Commit 291a1f3

Browse files
author
Gabor Horvath
committed
[cxx-interop] Add attribute to hide Swift declarations from interop
This can help work around problems when the names of a C++ declaration and a Swift declaration would collide, or to temporarily work around compiler bugs. rdar://152838988&140802127
1 parent 31408fe commit 291a1f3

File tree

7 files changed

+70
-1
lines changed

7 files changed

+70
-1
lines changed

include/swift/AST/AttrKind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ enum class ENUM_EXTENSIBILITY_ATTR(closed) EffectsKind : uint8_t {
9797
/// This enum represents the possible values of the @_expose attribute.
9898
enum class ENUM_EXTENSIBILITY_ATTR(closed) ExposureKind : uint8_t {
9999
Cxx SWIFT_NAME("cxx"),
100+
NotCxx SWIFT_NAME("notcxx"),
100101
Wasm SWIFT_NAME("wasm"),
101102
Last_ExposureKind = Wasm
102103
};

lib/AST/Attr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,9 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
12531253
case ExposureKind::Cxx:
12541254
Printer << "(Cxx";
12551255
break;
1256+
case ExposureKind::NotCxx:
1257+
Printer << "(!Cxx";
1258+
break;
12561259
}
12571260
if (!cast<ExposeAttr>(this)->Name.empty())
12581261
Printer << ", \"" << cast<ExposeAttr>(this)->Name << "\"";

lib/Parse/ParseDecl.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3064,13 +3064,22 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
30643064
"Cxx");
30653065
ParseSymbolName = false;
30663066
};
3067+
bool isNegated = false;
3068+
if (Tok.is(tok::oper_prefix) && Tok.getText() == "!") {
3069+
isNegated = true;
3070+
consumeToken(tok::oper_prefix);
3071+
}
30673072
if (Tok.isNot(tok::identifier)) {
30683073
diagnoseExpectOption();
30693074
return makeParserSuccess();
30703075
}
30713076
if (Tok.getText() == "Cxx") {
3072-
ExpKind = ExposureKind::Cxx;
3077+
ExpKind = isNegated ? ExposureKind::NotCxx : ExposureKind::Cxx;
30733078
} else if (Tok.getText() == "wasm") {
3079+
if (isNegated) {
3080+
diagnoseExpectOption();
3081+
return makeParserSuccess();
3082+
}
30743083
ExpKind = ExposureKind::Wasm;
30753084
} else {
30763085
diagnoseExpectOption();

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/ASTContext.h"
2323
#include "swift/AST/ASTMangler.h"
2424
#include "swift/AST/ASTVisitor.h"
25+
#include "swift/AST/Attr.h"
2526
#include "swift/AST/ClangSwiftTypeCorrespondence.h"
2627
#include "swift/AST/Comment.h"
2728
#include "swift/AST/ConformanceLookup.h"
@@ -2950,6 +2951,17 @@ static bool excludeForObjCImplementation(const ValueDecl *VD) {
29502951
return false;
29512952
}
29522953

2954+
static bool hasExposeNotCxxAttr(const ValueDecl *VD) {
2955+
for (const auto *attr : VD->getAttrs().getAttributes<ExposeAttr>())
2956+
if (attr->getExposureKind() == ExposureKind::NotCxx)
2957+
return true;
2958+
if (const auto *NMT = dyn_cast<NominalTypeDecl>(VD->getDeclContext()))
2959+
return hasExposeNotCxxAttr(NMT);
2960+
if (const auto *ED = dyn_cast<ExtensionDecl>(VD->getDeclContext()))
2961+
return hasExposeNotCxxAttr(ED->getExtendedNominal());
2962+
return false;
2963+
}
2964+
29532965
static bool isExposedToThisModule(const ModuleDecl &M, const ValueDecl *VD,
29542966
const llvm::StringSet<> &exposedModules) {
29552967
if (VD->hasClangNode())
@@ -3001,6 +3013,9 @@ bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
30013013
if (requiresExposedAttribute && !hasExposeAttr(VD))
30023014
return false;
30033015

3016+
if (hasExposeNotCxxAttr(VD))
3017+
return false;
3018+
30043019
if (!isVisible(VD))
30053020
return false;
30063021

lib/Sema/TypeCheckAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "TypeCheckType.h"
2424
#include "TypeChecker.h"
2525
#include "swift/AST/ASTVisitor.h"
26+
#include "swift/AST/Attr.h"
27+
#include "swift/AST/AttrKind.h"
2628
#include "swift/AST/AvailabilityInference.h"
2729
#include "swift/AST/ClangModuleLoader.h"
2830
#include "swift/AST/ConformanceLookup.h"
@@ -2415,6 +2417,12 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
24152417
diagnose(attr->getLocation(), diag::expose_wasm_not_at_top_level_func);
24162418
break;
24172419
}
2420+
case ExposureKind::NotCxx:
2421+
for (const auto *attr : D->getAttrs().getAttributes<ExposeAttr>())
2422+
if (attr->getExposureKind() == ExposureKind::Cxx)
2423+
diagnose(attr->getLocation(), diag::expose_only_non_other_attr,
2424+
"@_expose(Cxx)");
2425+
break;
24182426
case ExposureKind::Cxx: {
24192427
auto *VD = cast<ValueDecl>(D);
24202428
// Expose cannot be mixed with '@_cdecl' declarations.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -module-name SwiftPrivate -clang-header-expose-decls=all-public -typecheck -verify -emit-clang-header-path %t/swiftprivate.h
3+
// RUN: %FileCheck %s < %t/swiftprivate.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/swiftprivate.h -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)
6+
7+
public struct Exposed {
8+
public var x: Int
9+
@_expose(!Cxx)
10+
public var notExposedField: Int
11+
}
12+
13+
@_expose(!Cxx)
14+
public struct NotExposed {
15+
16+
}
17+
18+
extension NotExposed {
19+
func notExposed() {}
20+
}
21+
22+
@_expose(!Cxx)
23+
public func NotExposedfunction() {}
24+
25+
// CHECK-NOT: NotExposed
26+
// CHECK-NOT: notExposed
27+
// CHECK: Exposed

test/attr/attr_expose.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ func incorrectLangSpecifier() {}
1515
@_expose(Cxx) @_cdecl("test") // expected-error {{'@_expose' cannot be applied to an '@_cdecl' declaration}}
1616
func cdeclAndExpose() {}
1717

18+
@_expose(Cxx) @_expose(!Cxx) // expected-error {{'@_expose' cannot be applied to an '@_expose(Cxx)' declaration}}
19+
func contradictingExpose() {}
20+
21+
@_expose(!Cxx) @_expose(Cxx) // expected-error {{'@_expose' cannot be applied to an '@_expose(Cxx)' declaration}}
22+
func contradictingExpose2() {}
23+
1824
func hasNested() {
1925
@_expose(Cxx) // expected-error{{can only be used in a non-local scope}}
2026
func nested() { }

0 commit comments

Comments
 (0)