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
3 changes: 3 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
/// Check if this is a std.string type from C++.
bool isCxxString();

/// Check if this is the type Unicode.Scalar from the Swift standard library.
bool isUnicodeScalar();

/// Check if this type is known to represent key paths.
bool isKnownKeyPathType();

Expand Down
19 changes: 19 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,25 @@ bool TypeBase::isCxxString() {
ctx.Id_basic_string.is(clangDecl->getName());
}

bool TypeBase::isUnicodeScalar() {
if (!is<StructType>())
return false;
const auto *structType = castTo<StructType>();
if (!structType->getDecl()->getName().is("Scalar"))
return false;

Type parent = structType->getParent();
if (!parent->is<EnumType>())
return false;
const auto enumDecl = parent->castTo<EnumType>()->getDecl();
if (!enumDecl->getName().is("Unicode"))
return false;
const auto *parentDC = enumDecl->getDeclContext();
if (!parentDC->isModuleScopeContext() && parentDC->getParentModule()->isStdlibModule())
return false;
return true;
}

bool TypeBase::isKnownKeyPathType() {
return isKeyPath() || isWritableKeyPath() || isReferenceWritableKeyPath() ||
isPartialKeyPath() || isAnyKeyPath();
Expand Down
16 changes: 15 additions & 1 deletion lib/ClangImporter/ClangIncludePaths.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,21 @@ static void getLibStdCxxFileMapping(
"bits/unique_lock.h", "bits/unique_ptr.h", "bits/unordered_map.h",
"bits/unordered_set.h", "bits/uses_allocator.h",
"bits/uses_allocator_args.h", "bits/valarray_after.h",
"bits/valarray_array.h", "bits/valarray_before.h"};
"bits/valarray_array.h", "bits/valarray_before.h", "bits/version.h",
// C++20 and newer:
"barrier",
"compare",
"concepts",
"format",
"latch",
"numbers",
"ranges",
"semaphore",
"source_location",
"span",
"stop_token",
"syncstream",
};
std::string additionalHeaderDirectives;
llvm::raw_string_ostream os(additionalHeaderDirectives);
os << contents.substr(0, headerInjectionPoint);
Expand Down
10 changes: 8 additions & 2 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4675,8 +4675,14 @@ namespace {
// Do not attempts to import ObjCBool values, for similar reasons.
bool isObjCBool = (type && type->isObjCBool()) ||
(type && synthesizer.isObjCBool(type));

if (type && !isCGFloat && !isObjCBool) {
// Do not attempts to import CWideChar (wchar_t) values. CWideChar is
// a typealias for Unicode.Scalar, which does not
// implement _ExpressibleByBuiltinIntegerLiteral.
// FIXME: import using _ExpressibleByUnicodeScalarLiteral.
Comment on lines +4678 to +4681
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a source breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change only affects sources that would previously trigger an assert, so I would not say it's source breaking.

bool isUnicodeScalar = (type && type->isUnicodeScalar()) ||
(type && synthesizer.isUnicodeScalar(type));

if (type && !isCGFloat && !isObjCBool && !isUnicodeScalar) {
auto convertKind = ConstantConvertKind::None;
// Request conversions on enums, and swift_wrapper((enum/struct))
// types
Expand Down
10 changes: 10 additions & 0 deletions lib/ClangImporter/SwiftDeclSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,16 @@ bool SwiftDeclSynthesizer::isObjCBool(Type type) {
return importTy->isObjCBool();
}

bool SwiftDeclSynthesizer::isUnicodeScalar(Type type) {
auto found = ImporterImpl.RawTypes.find(type->getAnyNominal());
if (found == ImporterImpl.RawTypes.end()) {
return false;
}

Type importTy = found->second;
return importTy->isUnicodeScalar();
}

ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name,
DeclContext *dc, Type type,
const clang::APValue &value,
Expand Down
2 changes: 2 additions & 0 deletions lib/ClangImporter/SwiftDeclSynthesizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ class SwiftDeclSynthesizer {

bool isObjCBool(Type type);

bool isUnicodeScalar(Type type);

private:
Type getConstantLiteralType(Type type, ConstantConvertKind convertKind);

Expand Down
1 change: 0 additions & 1 deletion stdlib/public/Cxx/libstdcxx/libstdcxx.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ module std {
header "ostream"
header "queue"
header "set"
header "span"
header "sstream"
header "stack"
header "stdexcept"
Expand Down
4 changes: 4 additions & 0 deletions test/Interop/C/chars/Inputs/import-cchar-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
extern char a_char;
extern wchar_t a_wchar;

// This case is a regression test for a crash when importing constant initializers for wchar_t,
// since Unicode.Scalar cannot be initialized with integer literals.
const wchar_t an_initialized_wchar = 2;

#if __cplusplus
extern char8_t small_char;
#endif
Expand Down
1 change: 1 addition & 0 deletions test/Interop/C/chars/import-cchar-types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@

// CHECK: var a_char: CChar
// CHECK: var a_wchar: wchar_t
// CHECK: var an_initialized_wchar: wchar_t { get }

// CHECK-CXX: var small_char: UInt8