Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 include/swift/AST/AttrKind.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ enum class ENUM_EXTENSIBILITY_ATTR(closed) EffectsKind : uint8_t {
/// This enum represents the possible values of the @_expose attribute.
enum class ENUM_EXTENSIBILITY_ATTR(closed) ExposureKind : uint8_t {
Cxx SWIFT_NAME("cxx"),
NotCxx SWIFT_NAME("notcxx"),
Wasm SWIFT_NAME("wasm"),
Last_ExposureKind = Wasm
};
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,8 @@ ERROR(expose_only_non_other_attr,none,
ERROR(expose_inside_unexposed_decl,none,
"'@_expose' cannot be applied inside of unexposed declaration %0",
(const ValueDecl *))
ERROR(expose_redundant_name_provided, none,
"'@_expose(!Cxx)' does not accept a name argument", ())
ERROR(expose_invalid_name_pattern_init,none,
"invalid declaration name '%0' specified in '@_expose'; "
"exposed initializer name must start with 'init'", (StringRef))
Expand Down
3 changes: 3 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,9 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
case ExposureKind::Cxx:
Printer << "(Cxx";
break;
case ExposureKind::NotCxx:
Printer << "(!Cxx";
break;
}
if (!cast<ExposeAttr>(this)->Name.empty())
Printer << ", \"" << cast<ExposeAttr>(this)->Name << "\"";
Expand Down
11 changes: 10 additions & 1 deletion lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3079,13 +3079,22 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
"Cxx");
ParseSymbolName = false;
};
bool isNegated = false;
if (Tok.is(tok::oper_prefix) && Tok.getText() == "!") {
isNegated = true;
consumeToken(tok::oper_prefix);
}
if (Tok.isNot(tok::identifier)) {
diagnoseExpectOption();
return makeParserSuccess();
}
if (Tok.getText() == "Cxx") {
ExpKind = ExposureKind::Cxx;
ExpKind = isNegated ? ExposureKind::NotCxx : ExposureKind::Cxx;
} else if (Tok.getText() == "wasm") {
if (isNegated) {
diagnoseExpectOption();
return makeParserSuccess();
}
ExpKind = ExposureKind::Wasm;
} else {
diagnoseExpectOption();
Expand Down
15 changes: 15 additions & 0 deletions lib/PrintAsClang/DeclAndTypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Attr.h"
#include "swift/AST/ClangSwiftTypeCorrespondence.h"
#include "swift/AST/Comment.h"
#include "swift/AST/ConformanceLookup.h"
Expand Down Expand Up @@ -2976,6 +2977,17 @@ static bool excludeForObjCImplementation(const ValueDecl *VD) {
return false;
}

bool swift::hasExposeNotCxxAttr(const ValueDecl *VD) {
for (const auto *attr : VD->getAttrs().getAttributes<ExposeAttr>())
if (attr->getExposureKind() == ExposureKind::NotCxx)
return true;
if (const auto *NMT = dyn_cast<NominalTypeDecl>(VD->getDeclContext()))
return hasExposeNotCxxAttr(NMT);
if (const auto *ED = dyn_cast<ExtensionDecl>(VD->getDeclContext()))
return hasExposeNotCxxAttr(ED->getExtendedNominal());
return false;
}

static bool isExposedToThisModule(const ModuleDecl &M, const ValueDecl *VD,
const llvm::StringSet<> &exposedModules) {
if (VD->hasClangNode())
Expand Down Expand Up @@ -3027,6 +3039,9 @@ bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
if (requiresExposedAttribute && !hasExposeAttr(VD))
return false;

if (hasExposeNotCxxAttr(VD))
return false;

if (!isVisible(VD))
return false;

Expand Down
2 changes: 2 additions & 0 deletions lib/PrintAsClang/DeclAndTypePrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ class DeclAndTypePrinter {

bool isStringNestedType(const ValueDecl *VD, StringRef Typename);

bool hasExposeNotCxxAttr(const ValueDecl *VD);

} // end namespace swift

#endif
6 changes: 4 additions & 2 deletions lib/PrintAsClang/ModuleContentsWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,8 @@ class ModuleWriter {
// library. Also skip structs from the standard library, they can cause
// ambiguities because of the arithmetic types that conflict with types we
// already have in `swift::` namespace. Also skip `Error` protocol from
// stdlib, we have experimental support for it.
// stdlib, we have experimental support for it. Also skip explicitly exluded
// declarations.
removedVDList.erase(
llvm::remove_if(
removedVDList,
Expand All @@ -1073,7 +1074,8 @@ class ModuleWriter {
vd->getBaseIdentifier().hasUnderscoredNaming()) ||
(vd->isStdlibDecl() && isa<StructDecl>(vd)) ||
(vd->isStdlibDecl() &&
vd->getASTContext().getErrorDecl() == vd);
vd->getASTContext().getErrorDecl() == vd) ||
swift::hasExposeNotCxxAttr(vd);
}),
removedVDList.end());
// Sort the unavaiable decls by their name and kind.
Expand Down
10 changes: 10 additions & 0 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "TypeChecker.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Attr.h"
#include "swift/AST/AttrKind.h"
#include "swift/AST/AvailabilityInference.h"
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/ConformanceLookup.h"
Expand Down Expand Up @@ -2462,6 +2464,14 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
diagnose(attr->getLocation(), diag::expose_wasm_not_at_top_level_func);
break;
}
case ExposureKind::NotCxx:
for (const auto *attr : D->getAttrs().getAttributes<ExposeAttr>())
if (attr->getExposureKind() == ExposureKind::Cxx)
diagnose(attr->getLocation(), diag::expose_only_non_other_attr,
"@_expose(Cxx)");
if (!attr->Name.empty())
diagnose(attr->getLocation(), diag::expose_redundant_name_provided);
break;
case ExposureKind::Cxx: {
auto *VD = cast<ValueDecl>(D);
// Expose cannot be mixed with '@_cdecl' declarations.
Expand Down
33 changes: 33 additions & 0 deletions test/Interop/SwiftToCxx/expose-attr/hidden-decls.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -module-name SwiftPrivate -clang-header-expose-decls=all-public -typecheck -verify -emit-clang-header-path %t/swiftprivate.h
// RUN: %FileCheck %s < %t/swiftprivate.h

// RUN: %check-interop-cxx-header-in-clang(%t/swiftprivate.h -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)

public struct Exposed {
public var x: Int
@_expose(!Cxx)
public var notExposedField: Int
}

@_expose(!Cxx)
public struct NotExposed {
public var x: Int
}

extension NotExposed {
func notExposed() {}
}

@_expose(!Cxx)
public func NotExposedfunction() {}

@MainActor
@_expose(!Cxx)
public class UnavailableClass {
}

// CHECK-NOT: NotExposed
// CHECK-NOT: notExposed
// CHECK: Exposed
// CHECK-NOT: UnavailableClass
9 changes: 9 additions & 0 deletions test/attr/attr_expose.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ func incorrectLangSpecifier() {}
@_expose(Cxx) @_cdecl("test") // expected-error {{'@_expose' cannot be applied to an '@_cdecl' declaration}}
func cdeclAndExpose() {}

@_expose(Cxx) @_expose(!Cxx) // expected-error {{'@_expose' cannot be applied to an '@_expose(Cxx)' declaration}}
func contradictingExpose() {}

@_expose(!Cxx) @_expose(Cxx) // expected-error {{'@_expose' cannot be applied to an '@_expose(Cxx)' declaration}}
func contradictingExpose2() {}

@_expose(!Cxx, "name") // expected-error {{'@_expose(!Cxx)' does not accept a name argument}}
func notExposeWithName() {}

func hasNested() {
@_expose(Cxx) // expected-error{{can only be used in a non-local scope}}
func nested() { }
Expand Down