Skip to content

Commit d8c8f65

Browse files
authored
Merge pull request #79206 from beccadax/this-name-is-not-constructive
Diagnose and forbid invalid Swift names on inits
2 parents cca306a + 0466d5c commit d8c8f65

File tree

13 files changed

+172
-97
lines changed

13 files changed

+172
-97
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
66
## Swift 6.1
77

8+
* Previous versions of Swift would incorrectly allow Objective-C `-init...`
9+
methods with custom Swift names to be imported as initializers, but with base
10+
names other than `init`. The compiler now diagnoses these attributes and
11+
infers a name for the initializer as though they are not present.
12+
813
* Projected value initializers are now correctly injected into calls when
914
an argument exactly matches a parameter with an external property wrapper.
1015

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ ERROR(dump_pcm_error,Fatal,
5454
WARNING(invalid_swift_name_method,none,
5555
"too %select{few|many}0 parameters in swift_name attribute (expected %1; "
5656
"got %2)", (bool, unsigned, unsigned))
57+
WARNING(invalid_swift_name_for_decl,none,
58+
"custom Swift name '%0' ignored because it is not valid for %kindonly1; "
59+
"imported as %1 instead",
60+
(StringRef, ValueDecl *))
5761

5862
NOTE(note_while_importing, none, "while importing '%0'", (StringRef))
5963
ERROR(swift_name_protocol_static, none, "swift_name cannot be used to define "

include/swift/Frontend/DiagnosticVerifier.h

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ struct LineColumnRange {
4545
};
4646

4747
class CapturedFixItInfo final {
48+
SourceManager *diagSM;
4849
DiagnosticInfo::FixIt FixIt;
4950
mutable LineColumnRange LineColRange;
5051

5152
public:
52-
CapturedFixItInfo(DiagnosticInfo::FixIt FixIt) : FixIt(FixIt) {}
53+
CapturedFixItInfo(SourceManager &diagSM, DiagnosticInfo::FixIt FixIt)
54+
: diagSM(&diagSM), FixIt(FixIt) {}
5355

5456
CharSourceRange &getSourceRange() { return FixIt.getRange(); }
5557
const CharSourceRange &getSourceRange() const { return FixIt.getRange(); }
@@ -58,13 +60,12 @@ class CapturedFixItInfo final {
5860

5961
/// Obtain the line-column range corresponding to the fix-it's
6062
/// replacement range.
61-
const LineColumnRange &getLineColumnRange(const SourceManager &SM,
62-
unsigned BufferID) const;
63+
const LineColumnRange &getLineColumnRange(SourceManager &SM) const;
6364
};
6465

6566
struct CapturedDiagnosticInfo {
6667
llvm::SmallString<128> Message;
67-
llvm::SmallString<32> FileName;
68+
std::optional<unsigned> SourceBufferID;
6869
DiagnosticKind Classification;
6970
SourceLoc Loc;
7071
unsigned Line;
@@ -73,14 +74,14 @@ struct CapturedDiagnosticInfo {
7374
SmallVector<std::string, 1> EducationalNotes;
7475

7576
CapturedDiagnosticInfo(llvm::SmallString<128> Message,
76-
llvm::SmallString<32> FileName,
77+
std::optional<unsigned> SourceBufferID,
7778
DiagnosticKind Classification, SourceLoc Loc,
7879
unsigned Line, unsigned Column,
7980
SmallVector<CapturedFixItInfo, 2> FixIts,
8081
SmallVector<std::string, 1> EducationalNotes)
81-
: Message(Message), FileName(FileName), Classification(Classification),
82-
Loc(Loc), Line(Line), Column(Column), FixIts(FixIts),
83-
EducationalNotes(EducationalNotes) {
82+
: Message(Message), SourceBufferID(SourceBufferID),
83+
Classification(Classification), Loc(Loc), Line(Line), Column(Column),
84+
FixIts(FixIts), EducationalNotes(EducationalNotes) {
8485
std::sort(EducationalNotes.begin(), EducationalNotes.end());
8586
}
8687
};
@@ -91,25 +92,23 @@ class DiagnosticVerifier : public DiagnosticConsumer {
9192
SourceManager &SM;
9293
std::vector<CapturedDiagnosticInfo> CapturedDiagnostics;
9394
ArrayRef<unsigned> BufferIDs;
94-
SmallVector<unsigned, 4> AdditionalBufferIDs;
95+
ArrayRef<std::string> AdditionalFilePaths;
9596
bool AutoApplyFixes;
9697
bool IgnoreUnknown;
9798
bool UseColor;
9899
ArrayRef<std::string> AdditionalExpectedPrefixes;
99100

100101
public:
101102
explicit DiagnosticVerifier(SourceManager &SM, ArrayRef<unsigned> BufferIDs,
103+
ArrayRef<std::string> AdditionalFilePaths,
102104
bool AutoApplyFixes, bool IgnoreUnknown,
103105
bool UseColor,
104106
ArrayRef<std::string> AdditionalExpectedPrefixes)
105-
: SM(SM), BufferIDs(BufferIDs), AutoApplyFixes(AutoApplyFixes),
106-
IgnoreUnknown(IgnoreUnknown), UseColor(UseColor),
107+
: SM(SM), BufferIDs(BufferIDs), AdditionalFilePaths(AdditionalFilePaths),
108+
AutoApplyFixes(AutoApplyFixes), IgnoreUnknown(IgnoreUnknown),
109+
UseColor(UseColor),
107110
AdditionalExpectedPrefixes(AdditionalExpectedPrefixes) {}
108111

109-
void appendAdditionalBufferID(unsigned bufferID) {
110-
AdditionalBufferIDs.push_back(bufferID);
111-
}
112-
113112
virtual void handleDiagnostic(SourceManager &SM,
114113
const DiagnosticInfo &Info) override;
115114

lib/ClangImporter/ImportDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7323,6 +7323,14 @@ ConstructorDecl *SwiftDeclConverter::importConstructor(
73237323
// If this constructor overrides another constructor, mark it as such.
73247324
recordObjCOverride(result);
73257325

7326+
// If we ignored a custom Swift name because it wasn't suitable for an init,
7327+
// diagnose that now.
7328+
if (importedName.hasInvalidCustomName() && isActiveSwiftVersion()) {
7329+
if (auto customName = NameImporter::findCustomName(objcMethod, version)) {
7330+
result->diagnose(diag::invalid_swift_name_for_decl, *customName, result);
7331+
}
7332+
}
7333+
73267334
return result;
73277335
}
73287336

lib/ClangImporter/ImportName.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,15 @@ static StringRef renameUnsafeMethod(ASTContext &ctx,
15011501
return name;
15021502
}
15031503

1504+
std::optional<StringRef>
1505+
NameImporter::findCustomName(const clang::Decl *decl,
1506+
ImportNameVersion version) {
1507+
if (auto nameAttr = findSwiftNameAttr(decl, version)) {
1508+
return nameAttr->name;
1509+
}
1510+
return std::nullopt;
1511+
}
1512+
15041513
ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
15051514
ImportNameVersion version,
15061515
clang::DeclarationName givenName) {
@@ -1676,6 +1685,11 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
16761685
// Note that this is an initializer.
16771686
isInitializer = true;
16781687
}
1688+
} else if (shouldImportAsInitializer(method, version, initPrefixLength)) {
1689+
// This is an initializer, but its custom name is ill-formed. Ignore
1690+
// the swift_name attribute.
1691+
skipCustomName = true;
1692+
result.info.hasInvalidCustomName = true;
16791693
}
16801694
}
16811695

lib/ClangImporter/ImportName.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,16 @@ class ImportedName {
230230

231231
unsigned hasAsyncAlternateInfo: 1;
232232

233+
/// Whether this declaration had a custom name that was ignored because it
234+
/// was invalid.
235+
unsigned hasInvalidCustomName : 1;
236+
233237
Info()
234238
: errorInfo(), selfIndex(), initKind(CtorInitializerKind::Designated),
235239
accessorKind(ImportedAccessorKind::None), hasCustomName(false),
236240
droppedVariadic(false), importAsMember(false), hasSelfIndex(false),
237241
hasErrorInfo(false), hasAsyncInfo(false),
238-
hasAsyncAlternateInfo(false) {}
242+
hasAsyncAlternateInfo(false), hasInvalidCustomName(false) {}
239243
} info;
240244

241245
public:
@@ -313,6 +317,10 @@ class ImportedName {
313317
bool hasCustomName() const { return info.hasCustomName; }
314318
void setHasCustomName() { info.hasCustomName = true; }
315319

320+
/// Whether this declaration had a custom name that was ignored because it
321+
/// was invalid.
322+
bool hasInvalidCustomName() const { return info.hasInvalidCustomName; }
323+
316324
/// Whether this was one of a special class of Objective-C
317325
/// initializers for which we drop the variadic argument rather
318326
/// than refuse to import the initializer.
@@ -489,6 +497,10 @@ class NameImporter {
489497
importSymbolicCXXDecls = isEnabled;
490498
}
491499

500+
/// Retrieve a purported custom name even if it is invalid.
501+
static std::optional<StringRef>
502+
findCustomName(const clang::Decl *decl, ImportNameVersion version);
503+
492504
private:
493505
bool enableObjCInterop() const { return swiftCtx.LangOpts.EnableObjCInterop; }
494506

0 commit comments

Comments
 (0)