Skip to content

Commit b469389

Browse files
authored
Merge pull request #29670 from rjmccall/ciliainig-teyepee-sieeriiieaileiizieaitieieoiniie
Implement Swift serialization and deserialization of Clang types
2 parents fc9ad01 + faee21b commit b469389

29 files changed

+1238
-37
lines changed

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,10 @@ class ASTContext final {
595595
const FunctionType::ExtInfo incompleteExtInfo,
596596
FunctionTypeRepresentation trueRep);
597597

598+
/// Get the Swift declaration that a Clang declaration was exported from,
599+
/// if applicable.
600+
const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl);
601+
598602
/// Determine whether the given Swift type is representable in a
599603
/// given foreign language.
600604
ForeignRepresentationInfo

include/swift/AST/ClangModuleLoader.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
#define SWIFT_AST_CLANG_MODULE_LOADER_H
1515

1616
#include "swift/AST/ModuleLoader.h"
17+
#include "swift/Basic/TaggedUnion.h"
1718

1819
namespace clang {
1920
class ASTContext;
2021
class CompilerInstance;
22+
class Decl;
2123
class Preprocessor;
2224
class Sema;
2325
class TargetInfo;
@@ -26,6 +28,7 @@ class Type;
2628

2729
namespace swift {
2830

31+
class Decl;
2932
class DeclContext;
3033
class VisibleDeclConsumer;
3134

@@ -40,6 +43,69 @@ enum class ClangTypeKind {
4043
ObjCProtocol,
4144
};
4245

46+
/// A path for serializing a declaration.
47+
class StableSerializationPath {
48+
public:
49+
struct ExternalPath {
50+
enum ComponentKind {
51+
/// A named record type (but not a template specialization)
52+
Record,
53+
54+
/// A named enum type
55+
Enum,
56+
57+
/// A C++ namespace
58+
Namespace,
59+
60+
/// A typedef
61+
Typedef,
62+
63+
/// A typedef's anonymous tag declaration. Identifier is empty.
64+
TypedefAnonDecl,
65+
66+
/// An Objective-C interface.
67+
ObjCInterface,
68+
69+
/// An Objective-C protocol.
70+
ObjCProtocol,
71+
};
72+
73+
static bool requiresIdentifier(ComponentKind kind) {
74+
return kind != TypedefAnonDecl;
75+
}
76+
77+
SmallVector<std::pair<ComponentKind, Identifier>, 2> Path;
78+
79+
void add(ComponentKind kind, Identifier name) {
80+
Path.push_back({kind, name});
81+
}
82+
};
83+
private:
84+
TaggedUnion<void, const Decl *, ExternalPath> Union;
85+
86+
public:
87+
StableSerializationPath() {}
88+
StableSerializationPath(const Decl *d) : Union(d) {}
89+
StableSerializationPath(ExternalPath ext) : Union(ext) {}
90+
91+
explicit operator bool() const { return !Union.empty(); }
92+
93+
bool isSwiftDecl() const { return Union.isa<const Decl*>(); }
94+
const Decl *getSwiftDecl() const {
95+
assert(isSwiftDecl());
96+
return Union.get<const Decl*>();
97+
}
98+
99+
bool isExternalPath() const { return Union.isa<ExternalPath>(); }
100+
const ExternalPath &getExternalPath() const {
101+
assert(isExternalPath());
102+
return Union.get<ExternalPath>();
103+
}
104+
105+
SWIFT_DEBUG_DUMP;
106+
void dump(raw_ostream &os) const;
107+
};
108+
43109
class ClangModuleLoader : public ModuleLoader {
44110
private:
45111
virtual void anchor();
@@ -111,6 +177,41 @@ class ClangModuleLoader : public ModuleLoader {
111177
/// Print the Clang type.
112178
virtual void printClangType(const clang::Type *type,
113179
llvm::raw_ostream &os) const = 0;
180+
181+
/// Try to find a stable serialization path for the given declaration,
182+
/// if there is one.
183+
virtual StableSerializationPath
184+
findStableSerializationPath(const clang::Decl *decl) const = 0;
185+
186+
/// Try to resolve a stable serialization path down to the original
187+
/// declaration.
188+
virtual const clang::Decl *
189+
resolveStableSerializationPath(const StableSerializationPath &path) const = 0;
190+
191+
/// Determine whether the given type is serializable.
192+
///
193+
/// If \c checkCanonical is true, checks the canonical type,
194+
/// not the given possibly-sugared type. In general:
195+
/// - non-canonical representations should be preserving the
196+
/// sugared type even if it isn't serializable, since that
197+
/// maintains greater source fidelity;
198+
/// - semantic checks need to be checking the serializability
199+
/// of the canonical type, since it's always potentially
200+
/// necessary to serialize that (e.g. in SIL); and
201+
/// - serializers can try to serialize the sugared type to
202+
/// maintain source fidelity and just fall back on the canonical
203+
/// type if that's not possible.
204+
///
205+
/// The expectation here is that this predicate is meaningful
206+
/// independent of the actual form of serialization: the types
207+
/// that we can't reliably binary-serialize without an absolute
208+
/// Clang AST cross-reference are the same types that won't
209+
/// reliably round-trip through a textual format. At the very
210+
/// least, it's probably best to use conservative predicates
211+
/// that work both ways so that language behavior doesn't differ
212+
/// based on subtleties like the target module interface format.
213+
virtual bool isSerializable(const clang::Type *type,
214+
bool checkCanonical) const = 0;
114215
};
115216

116217
} // namespace swift

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,6 +2660,10 @@ ERROR(assoc_conformance_from_implementation_only_module,none,
26602660
"cannot use conformance of %0 to %1 in associated type %3 (inferred as "
26612661
"%4); %2 has been imported as implementation-only",
26622662
(Type, DeclName, Identifier, Type, Type))
2663+
ERROR(unexportable_clang_function_type,none,
2664+
"cannot export the underlying C type of the function type %0; "
2665+
"it may use anonymous types or types defined outside of a module",
2666+
(Type))
26632667

26642668
WARNING(warn_implementation_only_conflict,none,
26652669
"%0 inconsistently imported as implementation-only",

include/swift/AST/PrettyStackTrace.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include "swift/AST/Identifier.h"
2525
#include "swift/AST/Type.h"
2626

27+
namespace clang {
28+
class Type;
29+
}
30+
2731
namespace swift {
2832
class ASTContext;
2933
class Decl;
@@ -132,6 +136,17 @@ class PrettyStackTraceType : public llvm::PrettyStackTraceEntry {
132136
virtual void print(llvm::raw_ostream &OS) const;
133137
};
134138

139+
/// PrettyStackTraceClangType - Observe that we are processing a
140+
/// specific Clang type.
141+
class PrettyStackTraceClangType : public llvm::PrettyStackTraceEntry {
142+
const clang::Type *TheType;
143+
const char *Action;
144+
public:
145+
PrettyStackTraceClangType(const char *action, const clang::Type *type)
146+
: TheType(type), Action(action) {}
147+
virtual void print(llvm::raw_ostream &OS) const;
148+
};
149+
135150
/// Observe that we are processing a specific type representation.
136151
class PrettyStackTraceTypeRepr : public llvm::PrettyStackTraceEntry {
137152
ASTContext &Context;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,16 @@ class ClangImporter final : public ClangModuleLoader {
422422
SourceLoc loc) const override;
423423
void printClangType(const clang::Type *type,
424424
llvm::raw_ostream &os) const override;
425+
426+
StableSerializationPath
427+
findStableSerializationPath(const clang::Decl *decl) const override;
428+
429+
const clang::Decl *
430+
resolveStableSerializationPath(
431+
const StableSerializationPath &path) const override;
432+
433+
bool isSerializable(const clang::Type *type,
434+
bool checkCanonical) const override;
425435
};
426436

427437
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===- SwiftAbstractBasicReader.h - Clang serialization adapter -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file provides an intermediate CRTP class which implements most of
14+
// Clang's AbstractBasicReader interface, paralleling the behavior defined
15+
// in SwiftAbstractBasicWriter.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICREADER_H
20+
#define SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICREADER_H
21+
22+
#include "clang/AST/AbstractTypeReader.h"
23+
24+
// This include is required to instantiate the template code in
25+
// AbstractBasicReader.h, i.e. it's a workaround to an include-what-you-use
26+
// violation.
27+
#include "clang/AST/DeclObjC.h"
28+
29+
namespace swift {
30+
31+
/// An implementation of Clang's AbstractBasicReader interface for a Swift
32+
/// datastream-based reader. This is paired with the AbstractBasicWriter
33+
/// implementation in SwiftAbstractBasicWriter.h. Note that the general
34+
/// expectation is that the types and declarations involved will have passed
35+
/// a serializability check when this is used for actual deserialization.
36+
///
37+
/// The subclass must implement:
38+
/// uint64_t readUInt64();
39+
/// clang::IdentifierInfo *readIdentifier();
40+
/// clang::Stmt *readStmtRef();
41+
/// clang::Decl *readDeclRef();
42+
template <class Impl>
43+
class DataStreamBasicReader
44+
: public clang::serialization::DataStreamBasicReader<Impl> {
45+
using super = clang::serialization::DataStreamBasicReader<Impl>;
46+
public:
47+
using super::asImpl;
48+
using super::getASTContext;
49+
50+
DataStreamBasicReader(clang::ASTContext &ctx) : super(ctx) {}
51+
52+
/// Perform all the calls necessary to write out the given type.
53+
clang::QualType readTypeRef() {
54+
auto kind = clang::Type::TypeClass(asImpl().readUInt64());
55+
return clang::serialization::AbstractTypeReader<Impl>(asImpl()).read(kind);
56+
}
57+
58+
bool readBool() {
59+
return asImpl().readUInt64() != 0;
60+
}
61+
62+
uint32_t readUInt32() {
63+
return uint32_t(asImpl().readUInt64());
64+
}
65+
66+
clang::Selector readSelector() {
67+
uint64_t numArgsPlusOne = asImpl().readUInt64();
68+
69+
// The null case.
70+
if (numArgsPlusOne == 0)
71+
return clang::Selector();
72+
73+
unsigned numArgs = unsigned(numArgsPlusOne - 1);
74+
SmallVector<clang::IdentifierInfo *, 4> chunks;
75+
for (unsigned i = 0, e = std::max(numArgs, 1U); i != e; ++i)
76+
chunks.push_back(asImpl().readIdentifier());
77+
78+
return getASTContext().Selectors.getSelector(numArgs, chunks.data());
79+
}
80+
81+
clang::SourceLocation readSourceLocation() {
82+
// Always read null.
83+
return clang::SourceLocation();
84+
}
85+
86+
clang::QualType readQualType() {
87+
clang::Qualifiers quals = asImpl().readQualifiers();
88+
clang::QualType type = asImpl().readTypeRef();
89+
return getASTContext().getQualifiedType(type, quals);
90+
}
91+
};
92+
93+
}
94+
95+
#endif
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===- SwiftAbstractBasicWriter.h - Clang serialization adapter -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file provides an intermediate CRTP class which implements most of
14+
// Clang's AbstractBasicWriter interface, allowing largely the same logic
15+
// to be used for both the importer's "can this be serialized" checks and
16+
// the serializer's actual serialization logic.
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
#ifndef SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICWRITER_H
21+
#define SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICWRITER_H
22+
23+
#include "clang/AST/AbstractTypeWriter.h"
24+
25+
namespace swift {
26+
27+
/// An implementation of Clang's AbstractBasicWriter interface for a Swift
28+
/// datastream-based reader. This is paired with the AbstractBasicReader
29+
/// implementation in SwiftAbstractBasicReader.h. Note that the general
30+
/// expectation is that the types and declarations involved will have passed
31+
/// a serializability check when this is used for actual serialization.
32+
/// The code in this class is also used when implementing that
33+
/// serializability check and so must be a little more cautious.
34+
///
35+
/// The subclass must implement:
36+
/// void writeUInt64(uint64_t value);
37+
/// void writeIdentifier(const clang::IdentifierInfo *ident);
38+
/// void writeStmtRef(const clang::Stmt *stmt);
39+
/// void writeDeclRef(const clang::Decl *decl);
40+
template <class Impl>
41+
class DataStreamBasicWriter
42+
: public clang::serialization::DataStreamBasicWriter<Impl> {
43+
using super = clang::serialization::DataStreamBasicWriter<Impl>;
44+
public:
45+
using super::asImpl;
46+
47+
/// Perform all the calls necessary to write out the given type.
48+
void writeTypeRef(const clang::Type *type) {
49+
asImpl().writeUInt64(uint64_t(type->getTypeClass()));
50+
clang::serialization::AbstractTypeWriter<Impl>(asImpl()).write(type);
51+
}
52+
53+
void writeBool(bool value) {
54+
asImpl().writeUInt64(uint64_t(value));
55+
}
56+
57+
void writeUInt32(uint32_t value) {
58+
asImpl().writeUInt64(uint64_t(value));
59+
}
60+
61+
void writeSelector(clang::Selector selector) {
62+
if (selector.isNull()) {
63+
asImpl().writeUInt64(0);
64+
return;
65+
}
66+
67+
asImpl().writeUInt64(selector.getNumArgs() + 1);
68+
for (unsigned i = 0, e = std::max(selector.getNumArgs(), 1U); i != e; ++i)
69+
asImpl().writeIdentifier(selector.getIdentifierInfoForSlot(i));
70+
}
71+
72+
void writeSourceLocation(clang::SourceLocation loc) {
73+
// DataStreamBasicReader will always read null; the serializability
74+
// check overrides this to complain about non-null source locations.
75+
}
76+
77+
void writeQualType(clang::QualType type) {
78+
assert(!type.isNull());
79+
80+
auto split = type.split();
81+
asImpl().writeQualifiers(split.Quals);
82+
83+
// Just recursively visit the given type.
84+
asImpl().writeTypeRef(split.Ty);
85+
}
86+
};
87+
88+
}
89+
90+
#endif

0 commit comments

Comments
 (0)