Skip to content

Commit afc6332

Browse files
[Sema] Parse a Clang function type from the cType argument.
1 parent 3e7ab04 commit afc6332

File tree

7 files changed

+82
-4
lines changed

7 files changed

+82
-4
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class CompilerInstance;
2121
class Preprocessor;
2222
class Sema;
2323
class TargetInfo;
24+
class Type;
2425
} // namespace clang
2526

2627
namespace swift {
@@ -100,6 +101,12 @@ class ClangModuleLoader : public ModuleLoader {
100101
lookupRelatedEntity(StringRef clangName, ClangTypeKind kind,
101102
StringRef relatedEntityKind,
102103
llvm::function_ref<void(TypeDecl *)> receiver) = 0;
104+
105+
/// Try to parse the string as a Clang function type.
106+
///
107+
/// Returns null if there was a parsing failure.
108+
virtual const clang::Type *parseClangFunctionType(StringRef type,
109+
SourceLoc loc) const = 0;
103110
};
104111

105112
} // namespace swift

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3924,6 +3924,13 @@ ERROR(unsupported_convention,none,
39243924
"convention '%0' not supported", (StringRef))
39253925
ERROR(unreferenced_generic_parameter,none,
39263926
"generic parameter '%0' is not used in function signature", (StringRef))
3927+
ERROR(unexpected_ctype_for_non_c_convention,none,
3928+
"convention '%0' does not support the 'cType' argument label, did you "
3929+
"mean @convention(c, cType: \"%1\") or @convention(block, cType: \"%1\") "
3930+
"instead?", (StringRef, StringRef))
3931+
ERROR(unable_to_parse_c_function_type,none,
3932+
"unable to parse '%0'; it should be a C function pointer type or a "
3933+
"block pointer type", (StringRef))
39273934

39283935
// Opaque types
39293936
ERROR(unsupported_opaque_type,none,

include/swift/ClangImporter/ClangImporter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace clang {
4040
class NamedDecl;
4141
class Sema;
4242
class TargetInfo;
43+
class Type;
4344
class VisibleDeclConsumer;
4445
class DeclarationName;
4546
}
@@ -416,6 +417,9 @@ class ClangImporter final : public ClangModuleLoader {
416417
/// with -import-objc-header option.
417418
getPCHFilename(const ClangImporterOptions &ImporterOptions,
418419
StringRef SwiftPCHHash, bool &isExplicit);
420+
421+
const clang::Type *parseClangFunctionType(StringRef type,
422+
SourceLoc loc) const override;
419423
};
420424

421425
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,

lib/ClangImporter/ClangImporter.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3275,6 +3275,23 @@ void ClangImporter::verifyAllModules() {
32753275
#endif
32763276
}
32773277

3278+
const clang::Type *
3279+
ClangImporter::parseClangFunctionType(StringRef typeStr,
3280+
SourceLoc loc) const {
3281+
auto &sema = Impl.getClangSema();
3282+
StringRef filename = Impl.SwiftContext.SourceMgr.getDisplayNameForLoc(loc);
3283+
// TODO: Obtain a clang::SourceLocation from the swift::SourceLoc we have
3284+
auto parsedType = sema.ParseTypeFromStringCallback(typeStr, filename, {});
3285+
if (!parsedType.isUsable())
3286+
return nullptr;
3287+
clang::QualType resultType = clang::Sema::GetTypeFromParser(parsedType.get());
3288+
auto *typePtr = resultType.getTypePtrOrNull();
3289+
if (typePtr && (typePtr->isFunctionPointerType()
3290+
|| typePtr->isBlockPointerType()))
3291+
return typePtr;
3292+
return nullptr;
3293+
}
3294+
32783295
//===----------------------------------------------------------------------===//
32793296
// ClangModule Implementation
32803297
//===----------------------------------------------------------------------===//

lib/Sema/TypeCheckType.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,8 @@ namespace {
17991799
AnyFunctionType::Representation representation
18001800
= AnyFunctionType::Representation::Swift,
18011801
bool noescape = false,
1802+
const clang::Type *parsedClangFunctionType
1803+
= nullptr,
18021804
DifferentiabilityKind diffKind
18031805
= DifferentiabilityKind::NonDifferentiable);
18041806
bool
@@ -2166,7 +2168,31 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
21662168
// Function attributes require a syntactic function type.
21672169
auto *fnRepr = dyn_cast<FunctionTypeRepr>(repr);
21682170

2171+
auto tryParseClangType = [this](TypeAttributes::Convention &conv,
2172+
bool hasConventionCOrBlock)
2173+
-> const clang::Type * {
2174+
if (conv.ClangType.empty())
2175+
return nullptr;
2176+
if (!hasConventionCOrBlock) {
2177+
diagnose(conv.ClangTypeLoc,
2178+
diag::unexpected_ctype_for_non_c_convention,
2179+
conv.Name, conv.ClangType);
2180+
return nullptr;
2181+
}
2182+
2183+
StringRef filename =
2184+
Context.SourceMgr.getDisplayNameForLoc(conv.ClangTypeLoc);
2185+
const clang::Type *type = Context.getClangModuleLoader()
2186+
->parseClangFunctionType(conv.ClangType,
2187+
conv.ClangTypeLoc);
2188+
if (!type)
2189+
diagnose(conv.ClangTypeLoc, diag::unable_to_parse_c_function_type,
2190+
conv.ClangType);
2191+
return type;
2192+
};
2193+
21692194
if (fnRepr && hasFunctionAttr) {
2195+
const clang::Type *parsedClangFunctionType = nullptr;
21702196
if (options & TypeResolutionFlags::SILType) {
21712197
SILFunctionType::Representation rep;
21722198
TypeRepr *witnessMethodProtocol = nullptr;
@@ -2214,6 +2240,11 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22142240
rep = SILFunctionType::Representation::Thin;
22152241
} else {
22162242
rep = *parsedRep;
2243+
bool isCOrBlock =
2244+
rep == SILFunctionTypeRepresentation::CFunctionPointer
2245+
|| rep == SILFunctionTypeRepresentation::Block;
2246+
parsedClangFunctionType =
2247+
tryParseClangType(attrs.ConventionArguments.getValue(), isCOrBlock);
22172248
}
22182249

22192250
if (rep == SILFunctionType::Representation::WitnessMethod) {
@@ -2264,6 +2295,11 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22642295
rep = FunctionType::Representation::Swift;
22652296
} else {
22662297
rep = *parsedRep;
2298+
2299+
bool isCOrBlock = rep == FunctionTypeRepresentation::CFunctionPointer
2300+
|| rep == FunctionTypeRepresentation::Block;
2301+
parsedClangFunctionType =
2302+
tryParseClangType(attrs.ConventionArguments.getValue(), isCOrBlock);
22672303
}
22682304
}
22692305

@@ -2280,6 +2316,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22802316
}
22812317

22822318
ty = resolveASTFunctionType(fnRepr, options, rep, /*noescape=*/false,
2319+
parsedClangFunctionType,
22832320
diffKind);
22842321
if (!ty || ty->hasError())
22852322
return ty;
@@ -2593,6 +2630,7 @@ Type TypeResolver::resolveOpaqueReturnType(TypeRepr *repr,
25932630
Type TypeResolver::resolveASTFunctionType(
25942631
FunctionTypeRepr *repr, TypeResolutionOptions parentOptions,
25952632
AnyFunctionType::Representation representation, bool noescape,
2633+
const clang::Type *parsedClangFunctionType,
25962634
DifferentiabilityKind diffKind) {
25972635

25982636
TypeResolutionOptions options = None;
@@ -2631,8 +2669,9 @@ Type TypeResolver::resolveASTFunctionType(
26312669
noescape, repr->throws(), diffKind,
26322670
/*clangFunctionType*/nullptr);
26332671

2634-
const clang::Type *clangFnType = nullptr;
2635-
if (representation == AnyFunctionType::Representation::CFunctionPointer)
2672+
const clang::Type *clangFnType = parsedClangFunctionType;
2673+
if (representation == AnyFunctionType::Representation::CFunctionPointer
2674+
&& !clangFnType)
26362675
clangFnType = Context.getClangFunctionType(
26372676
params, outputTy, incompleteExtInfo,
26382677
AnyFunctionType::Representation::CFunctionPointer);

test/Parse/c_function_pointers.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ let f: @convention(c) (Int) -> Int = genericFunc // expected-error{{cannot be fo
5050

5151
func ct1() -> () { print("") }
5252

53-
let ct1ref0 : @convention(c, cType: "void *(void)") () -> () = ct1
54-
let ct1ref1 : @convention(c, cType: "void *(void)") = ct1 // expected-error{{expected type}}
53+
let ct1ref0 : @convention(c, cType: "void (*)(void)") () -> () = ct1
54+
let ct1ref1 : @convention(c, cType: "void (*)(void)") = ct1 // expected-error{{expected type}}
5555
let ct1ref2 : @convention(c, ) () -> () = ct1 // expected-error{{expected 'cType' label in 'convention' attribute}}
5656
let ct1ref3 : @convention(c, cType) () -> () = ct1 // expected-error{{expected ':' after 'cType' for 'convention' attribute}}
5757
let ct1ref4 : @convention(c, cType: ) () -> () = ct1 // expected-error{{expected string literal containing clang type for 'cType' in 'convention' attribute}}

test/attr/attr_convention.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
let f1: (Int) -> Int = { $0 }
44
let f2: @convention(swift) (Int) -> Int = { $0 }
5+
let f2a: @convention(swift, cType: "int *(int)") (Int32) -> Int32 = { $0 } // expected-error{{convention 'swift' does not support the 'cType' argument label, did you mean @convention(c, cType: "int *(int)") or @convention(block, cType: "int *(int)") instead?}}
56
let f3: @convention(block) (Int) -> Int = { $0 }
67
let f4: @convention(c) (Int) -> Int = { $0 }
8+
let f4a: @convention(c, cType: "int (int)") (Int32) -> Int32 = { $0 } // expected-error{{unable to parse 'int (int)'; it should be a C function pointer type or a block pointer type}}
9+
let f4b: @convention(c, cType: "void *") (Int32) -> Int32 = { $0 } // expected-error{{unable to parse 'void *'; it should be a C function pointer type or a block pointer type}}
10+
let f4c: @convention(c, cType: "int (*)(int)") (Int32) -> Int32 = { $0 }
711

812
let f5: @convention(INTERCAL) (Int) -> Int = { $0 } // expected-error{{convention 'INTERCAL' not supported}}
913

0 commit comments

Comments
 (0)