Skip to content

Commit 130f2de

Browse files
Nuri AmariNuriAmari
authored andcommitted
Improve ClangImporter failure diagnostics
This patch introduces new diagnostics to the ClangImporter to help explain why certain C, Objective-C or C++ declarations fail to import into Swift. This patch includes new diagnostics for the following entities: - C functions - C struct fields - Macros - Objective-C properties - Objective-C methods In particular, notes are attached to indicate when any of the above entities fail to import as a result of refering an incomplete (only forward declared) type. The new diangostics are hidden behind two new flags, -enable-experimental-clang-importer-diagnostics and -enable-experimental-eager-clang-module-diagnostics. The first flag emits diagnostics lazily, while the second eagerly imports all declarations visible from loaded Clang modules. The first flag is intended for day to day swiftc use, the second for module linting or debugging the importer.
1 parent d1bb98b commit 130f2de

36 files changed

+1567
-78
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,9 @@ class ASTContext final {
11601160
InheritedProtocolConformance *
11611161
getInheritedConformance(Type type, ProtocolConformance *inherited);
11621162

1163+
/// Check if \p decl is included in LazyContexts.
1164+
bool isLazyContext(const DeclContext *decl);
1165+
11631166
/// Get the lazy data for the given declaration.
11641167
///
11651168
/// \param lazyLoader If non-null, the lazy loader to use when creating the

include/swift/AST/ClangModuleLoader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ class ClangModuleLoader : public ModuleLoader {
182182
/// Imports a clang decl directly, rather than looking up its name.
183183
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
184184

185+
/// Emits any import diagnostics associated with the provided decl.
186+
virtual void diagnoseDeclDirectly(const clang::NamedDecl *decl) = 0;
187+
185188
/// Instantiate and import class template using given arguments.
186189
///
187190
/// This method will find the clang::ClassTemplateSpecialization decl if

include/swift/AST/DiagnosticEngine.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
#include "llvm/Support/SaveAndRestore.h"
3434
#include "llvm/Support/VersionTuple.h"
3535

36+
namespace clang {
37+
class NamedDecl;
38+
}
39+
3640
namespace swift {
3741
class Decl;
3842
class DeclAttribute;
@@ -116,7 +120,8 @@ namespace swift {
116120
VersionTuple,
117121
LayoutConstraint,
118122
ActorIsolation,
119-
Diagnostic
123+
Diagnostic,
124+
ClangDecl
120125
};
121126

122127
namespace diag {
@@ -149,6 +154,7 @@ namespace swift {
149154
LayoutConstraint LayoutConstraintVal;
150155
ActorIsolation ActorIsolationVal;
151156
DiagnosticInfo *DiagnosticVal;
157+
const clang::NamedDecl *ClangDecl;
152158
};
153159

154160
public:
@@ -251,6 +257,9 @@ namespace swift {
251257
DiagnosticVal(D) {
252258
}
253259

260+
DiagnosticArgument(const clang::NamedDecl *ND)
261+
: Kind(DiagnosticArgumentKind::ClangDecl), ClangDecl(ND) {}
262+
254263
/// Initializes a diagnostic argument using the underlying type of the
255264
/// given enum.
256265
template<
@@ -356,6 +365,11 @@ namespace swift {
356365
assert(Kind == DiagnosticArgumentKind::Diagnostic);
357366
return DiagnosticVal;
358367
}
368+
369+
const clang::NamedDecl *getAsClangDecl() const {
370+
assert(Kind == DiagnosticArgumentKind::ClangDecl);
371+
return ClangDecl;
372+
}
359373
};
360374

361375
/// Describes the current behavior to take with a diagnostic.
@@ -1327,18 +1341,20 @@ namespace swift {
13271341
builder();
13281342
}
13291343

1330-
/// Temporary on-stack storage and unescaping for encoded diagnostic
1331-
/// messages.
1332-
class EncodedDiagnosticMessage {
1333-
llvm::SmallString<128> Buf;
1344+
void printClangDeclName(const clang::NamedDecl *ND, llvm::raw_ostream &os);
13341345

1335-
public:
1336-
/// \param S A string with an encoded message
1337-
EncodedDiagnosticMessage(StringRef S);
1346+
/// Temporary on-stack storage and unescaping for encoded diagnostic
1347+
/// messages.
1348+
class EncodedDiagnosticMessage {
1349+
llvm::SmallString<128> Buf;
13381350

1339-
/// The unescaped message to display to the user.
1340-
const StringRef Message;
1341-
};
1351+
public:
1352+
/// \param S A string with an encoded message
1353+
EncodedDiagnosticMessage(StringRef S);
1354+
1355+
/// The unescaped message to display to the user.
1356+
const StringRef Message;
1357+
};
13421358

13431359
/// Returns a value that can be used to select between accessor kinds in
13441360
/// diagnostics.

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,30 @@ WARNING(import_multiple_mainactor_attr,none,
100100

101101
ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef))
102102

103+
NOTE(macro_not_imported_unsupported_operator, none, "operator not supported in macro arithmetic", ())
104+
NOTE(macro_not_imported_unsupported_named_operator, none, "operator '%0' not supported in macro arithmetic", (StringRef))
105+
NOTE(macro_not_imported_invalid_string_literal, none, "invalid string literal", ())
106+
NOTE(macro_not_imported_invalid_numeric_literal, none, "invalid numeric literal", ())
107+
NOTE(macro_not_imported_unsupported_literal, none, "only numeric and string macro literals supported", ())
108+
NOTE(macro_not_imported_nested_cast, none, "non-null nested casts not supported", ())
109+
110+
ERROR(macro_not_imported_function_like, none, "macro '%0' not imported: function like macros not supported", (StringRef))
111+
ERROR(macro_not_imported_unsupported_structure, none, "macro '%0' not imported: structure not supported", (StringRef))
112+
ERROR(macro_not_imported, none, "macro '%0' not imported", (StringRef))
113+
114+
NOTE(return_type_not_imported, none, "return type not imported", ())
115+
NOTE(parameter_type_not_imported, none, "parameter %0 not imported", (const clang::NamedDecl*))
116+
NOTE(incomplete_interface, none, "interface %0 is incomplete", (const clang::NamedDecl*))
117+
NOTE(incomplete_protocol, none, "protocol %0 is incomplete", (const clang::NamedDecl*))
118+
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
119+
120+
WARNING(record_field_not_imported, none, "field %0 not imported", (const clang::NamedDecl*))
121+
WARNING(invoked_func_not_imported, none, "function %0 not imported", (const clang::NamedDecl*))
122+
WARNING(record_method_not_imported, none, "method %0 not imported", (const clang::NamedDecl*))
123+
WARNING(objc_property_not_imported, none, "property %0 not imported", (const clang::NamedDecl*))
124+
125+
NOTE(forward_declared_interface_label, none, "interface %0 forward declared here", (const clang::NamedDecl*))
126+
NOTE(forward_declared_protocol_label, none, "protocol %0 forward declared here", (const clang::NamedDecl*))
127+
103128
#define UNDEFINE_DIAGNOSTIC_MACROS
104129
#include "DefineDiagnosticMacros.h"

include/swift/AST/LazyResolver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ class alignas(void*) LazyMemberLoader {
8585
loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
8686
uint64_t contextData) = 0;
8787

88+
virtual void diagnoseMissingNamedMember(const IterableDeclContext *IDC,
89+
DeclName name) = 0;
90+
8891
/// Populates the given vector with all conformances for \p D.
8992
///
9093
/// The implementation should \em not call setConformances on \p D.

include/swift/Basic/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,12 @@ namespace swift {
320320
/// Enable experimental flow-sensitive concurrent captures.
321321
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
322322

323+
/// Enable experimental ClangImporter diagnostics.
324+
bool EnableExperimentalClangImporterDiagnostics = false;
325+
326+
/// Enable experimental eager Clang module diagnostics.
327+
bool EnableExperimentalEagerClangModuleDiagnostics = false;
328+
323329
/// Enable inference of Sendable conformances for public types.
324330
bool EnableInferPublicSendable = false;
325331

include/swift/ClangImporter/ClangImporter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace clang {
4040
class EnumDecl;
4141
class MacroInfo;
4242
class Module;
43+
class ModuleMacro;
4344
class NamedDecl;
4445
class Sema;
4546
class TargetInfo;
@@ -109,6 +110,11 @@ class DWARFImporterDelegate {
109110
virtual void anchor();
110111
};
111112

113+
typedef llvm::PointerUnion<const clang::Decl *, const clang::MacroInfo *,
114+
const clang::ModuleMacro *, const clang::Type *,
115+
const clang::Token *>
116+
ImportDiagnosticTarget;
117+
112118
/// Class that imports Clang modules into Swift, mapping directly
113119
/// from Clang ASTs over to Swift ASTs.
114120
class ClangImporter final : public ClangModuleLoader {
@@ -509,6 +515,9 @@ class ClangImporter final : public ClangModuleLoader {
509515

510516
/// Imports a clang decl directly, rather than looking up it's name.
511517
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
518+
519+
/// Emits any pending diagnostics associated with the provided decl.
520+
void diagnoseDeclDirectly(const clang::NamedDecl *decl) override;
512521
};
513522

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

include/swift/Option/FrontendOptions.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,14 @@ def enable_experimental_flow_sensitive_concurrent_captures :
287287
Flag<["-"], "enable-experimental-flow-sensitive-concurrent-captures">,
288288
HelpText<"Enable flow-sensitive concurrent captures">;
289289

290+
def enable_experimental_clang_importer_diagnostics :
291+
Flag<["-"], "enable-experimental-clang-importer-diagnostics">,
292+
HelpText<"Enable experimental diagnostics when importing C, C++, and Objective-C libraries">;
293+
294+
def enable_experimental_eager_clang_module_diagnostics :
295+
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
296+
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;
297+
290298
def enable_resilience : Flag<["-"], "enable-resilience">,
291299
HelpText<"Deprecated, use -enable-library-evolution instead">;
292300
}

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,6 +2462,10 @@ ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) {
24622462
return result;
24632463
}
24642464

2465+
bool ASTContext::isLazyContext(const DeclContext *dc) {
2466+
return getImpl().LazyContexts.count(dc) != 0;
2467+
}
2468+
24652469
LazyContextData *ASTContext::getOrCreateLazyContextData(
24662470
const DeclContext *dc,
24672471
LazyMemberLoader *lazyLoader) {

lib/AST/DiagnosticEngine.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "swift/AST/DiagnosticEngine.h"
19-
#include "swift/AST/DiagnosticsCommon.h"
2019
#include "swift/AST/ASTContext.h"
2120
#include "swift/AST/ASTPrinter.h"
2221
#include "swift/AST/Decl.h"
2322
#include "swift/AST/DiagnosticSuppression.h"
23+
#include "swift/AST/DiagnosticsCommon.h"
2424
#include "swift/AST/Module.h"
2525
#include "swift/AST/Pattern.h"
2626
#include "swift/AST/PrintOptions.h"
@@ -30,6 +30,8 @@
3030
#include "swift/Config.h"
3131
#include "swift/Localization/LocalizationFormat.h"
3232
#include "swift/Parse/Lexer.h" // bad dependency
33+
#include "clang/AST/ASTContext.h"
34+
#include "clang/AST/Decl.h"
3335
#include "llvm/ADT/SmallString.h"
3436
#include "llvm/ADT/Twine.h"
3537
#include "llvm/Support/CommandLine.h"
@@ -566,6 +568,11 @@ static bool isMainActor(Type type) {
566568
return false;
567569
}
568570

571+
void swift::printClangDeclName(const clang::NamedDecl *ND,
572+
llvm::raw_ostream &os) {
573+
ND->getNameForDiagnostic(os, ND->getASTContext().getPrintingPolicy(), false);
574+
}
575+
569576
/// Format a single diagnostic argument and write it to the given
570577
/// stream.
571578
static void formatDiagnosticArgument(StringRef Modifier,
@@ -832,6 +839,13 @@ static void formatDiagnosticArgument(StringRef Modifier,
832839
diagArg->FormatArgs);
833840
break;
834841
}
842+
843+
case DiagnosticArgumentKind::ClangDecl:
844+
assert(Modifier.empty() && "Improper modifier for ClangDecl argument");
845+
Out << FormatOpts.OpeningQuotationMark;
846+
printClangDeclName(Arg.getAsClangDecl(), Out);
847+
Out << FormatOpts.ClosingQuotationMark;
848+
break;
835849
}
836850
}
837851

0 commit comments

Comments
 (0)