diff --git a/include/swift/Frontend/DiagnosticVerifier.h b/include/swift/Frontend/DiagnosticVerifier.h index 5eb293f793137..b254692486880 100644 --- a/include/swift/Frontend/DiagnosticVerifier.h +++ b/include/swift/Frontend/DiagnosticVerifier.h @@ -18,10 +18,15 @@ #ifndef SWIFT_FRONTEND_DIAGNOSTIC_VERIFIER_H #define SWIFT_FRONTEND_DIAGNOSTIC_VERIFIER_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "swift/AST/DiagnosticConsumer.h" #include "swift/Basic/LLVM.h" +namespace { +struct ExpectedDiagnosticInfo; +} + namespace swift { class DependencyTracker; class FileUnit; @@ -129,10 +134,25 @@ class DiagnosticVerifier : public DiagnosticConsumer { bool verifyUnknown(std::vector &CapturedDiagnostics) const; + std::vector Errors; + /// verifyFile - After the file has been processed, check to see if we /// got all of the expected diagnostics and check to see if there were any /// unexpected ones. Result verifyFile(unsigned BufferID); + unsigned parseExpectedDiagInfo(unsigned BufferID, StringRef MatchStart, + unsigned &PrevExpectedContinuationLine, + ExpectedDiagnosticInfo &Expected); + void + verifyDiagnostics(std::vector &ExpectedDiagnostics, + unsigned BufferID); + void verifyRemaining(std::vector &ExpectedDiagnostics, + const char *FileStart); + void addError(const char *Loc, const Twine &message, + ArrayRef FixIts = {}); + + std::optional + parseExpectedFixItRange(StringRef &Str, unsigned DiagnosticLineNo); bool checkForFixIt(const std::vector &ExpectedAlts, const CapturedDiagnosticInfo &D, unsigned BufferID) const; @@ -141,6 +161,8 @@ class DiagnosticVerifier : public DiagnosticConsumer { std::string renderFixits(ArrayRef ActualFixIts, unsigned BufferID, unsigned DiagnosticLineNo) const; + llvm::DenseMap Expansions; + void printRemainingDiagnostics() const; }; diff --git a/lib/Frontend/DiagnosticVerifier.cpp b/lib/Frontend/DiagnosticVerifier.cpp index 2cf53f226cf9a..41ea1e37c0269 100644 --- a/lib/Frontend/DiagnosticVerifier.cpp +++ b/lib/Frontend/DiagnosticVerifier.cpp @@ -28,6 +28,8 @@ using namespace swift; +const DiagnosticKind DiagnosticKindExpansion = DiagnosticKind((int)DiagnosticKind::Note + 1); + namespace { struct ExpectedCheckMatchStartParser { @@ -67,6 +69,13 @@ struct ExpectedCheckMatchStartParser { return true; } + if (MatchStart.starts_with("expansion")) { + ClassificationStartLoc = MatchStart.data(); + ExpectedClassification = DiagnosticKindExpansion; + MatchStart = MatchStart.substr(strlen("expansion")); + return true; + } + return false; } @@ -202,6 +211,7 @@ struct ExpectedDiagnosticInfo { std::string MessageStr; unsigned LineNo = ~0U; std::optional ColumnNo; + std::optional TargetBufferID; using AlternativeExpectedFixIts = std::vector; std::vector Fixits = {}; @@ -220,6 +230,8 @@ struct ExpectedDiagnosticInfo { }; std::optional DocumentationFile; + std::vector NestedDiags = {}; + ExpectedDiagnosticInfo(const char *ExpectedStart, const char *ClassificationStart, const char *ClassificationEnd, @@ -238,6 +250,8 @@ static std::string getDiagKindString(DiagnosticKind Kind) { return "note"; case DiagnosticKind::Remark: return "remark"; + case DiagnosticKindExpansion: + return "expansion"; } llvm_unreachable("Unhandled DiagKind in switch."); @@ -258,7 +272,7 @@ renderDocumentationFile(const std::string &documentationFile) { /// Otherwise return \c CapturedDiagnostics.end() with \c false. static std::tuple::iterator, bool> findDiagnostic(std::vector &CapturedDiagnostics, - const ExpectedDiagnosticInfo &Expected, unsigned BufferID) { + const ExpectedDiagnosticInfo &Expected, unsigned BufferID, SourceManager &SM) { auto fallbackI = CapturedDiagnostics.end(); for (auto I = CapturedDiagnostics.begin(), E = CapturedDiagnostics.end(); @@ -417,7 +431,20 @@ void DiagnosticVerifier::printDiagnostic(const llvm::SMDiagnostic &Diag) const { raw_ostream &stream = llvm::errs(); ColoredStream coloredStream{stream}; raw_ostream &out = UseColor ? coloredStream : stream; - SM.getLLVMSourceMgr().PrintMessage(out, Diag); + llvm::SourceMgr &Underlying = SM.getLLVMSourceMgr(); + Underlying.PrintMessage(out, Diag); + + SourceLoc Loc = SourceLoc::getFromPointer(Diag.getLoc().getPointer()); + if (Loc.isInvalid()) + return; + unsigned BufferID = SM.findBufferContainingLoc(Loc); + if (const GeneratedSourceInfo *GSI = SM.getGeneratedSourceInfo(BufferID)) { + SourceLoc ParentLoc = GSI->originalSourceRange.getStart(); + if (ParentLoc.isInvalid()) + return; + printDiagnostic(SM.GetMessage(ParentLoc, llvm::SourceMgr::DK_Note, + "in expansion from here", {}, {})); + } } std::string @@ -464,9 +491,9 @@ DiagnosticVerifier::renderFixits(ArrayRef ActualFixIts, /// /// \param DiagnosticLineNo The line number of the associated expected /// diagnostic; used to turn line offsets into line numbers. -static std::optional parseExpectedFixItRange( - StringRef &Str, unsigned DiagnosticLineNo, - llvm::function_ref diagnoseError) { +std::optional +DiagnosticVerifier::parseExpectedFixItRange(StringRef &Str, + unsigned DiagnosticLineNo) { assert(!Str.empty()); struct ParsedLineAndColumn { @@ -496,10 +523,10 @@ static std::optional parseExpectedFixItRange( unsigned FirstVal = 0; if (Str.consumeInteger(10, FirstVal)) { if (LineOffsetKind == OffsetKind::None) { - diagnoseError(Str.data(), + addError(Str.data(), "expected line or column number in fix-it verification"); } else { - diagnoseError(Str.data(), + addError(Str.data(), "expected line offset after leading '+' or '-' in fix-it " "verification"); } @@ -513,7 +540,7 @@ static std::optional parseExpectedFixItRange( return ParsedLineAndColumn{std::nullopt, FirstVal}; } - diagnoseError(Str.data(), + addError(Str.data(), "expected colon-separated column number after line offset " "in fix-it verification"); return std::nullopt; @@ -522,7 +549,7 @@ static std::optional parseExpectedFixItRange( unsigned Column = 0; Str = Str.drop_front(); if (Str.consumeInteger(10, Column)) { - diagnoseError(Str.data(), + addError(Str.data(), "expected column number after ':' in fix-it verification"); return std::nullopt; } @@ -555,7 +582,7 @@ static std::optional parseExpectedFixItRange( if (!Str.empty() && Str.front() == '-') { Str = Str.drop_front(); } else { - diagnoseError(Str.data(), + addError(Str.data(), "expected '-' range separator in fix-it verification"); return std::nullopt; } @@ -593,319 +620,375 @@ static void validatePrefixList(ArrayRef prefixes) { } } -/// After the file has been processed, check to see if we got all of -/// the expected diagnostics and check to see if there were any unexpected -/// ones. -DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { - using llvm::SMLoc; - +static bool parseTargetBufferName(StringRef &MatchStart, StringRef &Out, size_t &TextStartIdx) { + StringRef Offs = MatchStart.slice(0, TextStartIdx); + + size_t LineIndex = Offs.find(':'); + if (LineIndex == 0 || LineIndex == StringRef::npos) + return false; + Out = Offs.slice(1, LineIndex); + MatchStart = MatchStart.substr(LineIndex); + TextStartIdx -= LineIndex; + return true; +} + +unsigned DiagnosticVerifier::parseExpectedDiagInfo( + unsigned BufferID, StringRef MatchStartIn, + unsigned &PrevExpectedContinuationLine, + ExpectedDiagnosticInfo &Expected) { const SourceLoc BufferStartLoc = SM.getLocForBufferStart(BufferID); StringRef InputFile = SM.getEntireTextForBuffer(BufferID); - // Queue up all of the diagnostics, allowing us to sort them and emit them in - // file order. - std::vector Errors; + StringRef MatchStart = MatchStartIn; + const char *DiagnosticLoc = MatchStart.data(); + MatchStart = MatchStart.substr(strlen("expected-")); - unsigned PrevExpectedContinuationLine = 0; - - std::vector ExpectedDiagnostics; + const char *ClassificationStartLoc = nullptr; + std::optional ExpectedClassification; + { + ExpectedCheckMatchStartParser parser(MatchStart); + // If we fail to parse... continue. + if (!parser.parse(AdditionalExpectedPrefixes)) { + return 0; + } + MatchStart = parser.MatchStart; + ClassificationStartLoc = parser.ClassificationStartLoc; + ExpectedClassification = parser.ExpectedClassification; + } + assert(ClassificationStartLoc); + assert(bool(ExpectedClassification)); + + // Skip any whitespace before the {{. + MatchStart = MatchStart.substr(MatchStart.find_first_not_of(" \t")); + + size_t TextStartIdx = MatchStart.find("{{"); + if (TextStartIdx >= + MatchStart.find("\n")) { // Either not found, or found beyond next \n + addError(MatchStart.data(), + "expected {{ in expected-warning/note/error/expansion line"); + return 0; + } - auto addError = [&](const char *Loc, const Twine &message, - ArrayRef FixIts = {}) { - auto loc = SourceLoc::getFromPointer(Loc); - auto diag = SM.GetMessage(loc, llvm::SourceMgr::DK_Error, message, - {}, FixIts); - Errors.push_back(diag); - }; + Expected = ExpectedDiagnosticInfo(DiagnosticLoc, ClassificationStartLoc, + /*ClassificationEndLoc=*/MatchStart.data(), + *ExpectedClassification); + int LineOffset = 0; + bool AbsoluteLine = false; + + if (TextStartIdx > 0 && MatchStart[0] == '@') { + if (MatchStart[1] != '+' && MatchStart[1] != '-' && MatchStart[1] != ':' && (MatchStart[1] < '0' || MatchStart[1] > '9')) { + StringRef TargetBufferName; + if (!parseTargetBufferName(MatchStart, TargetBufferName, TextStartIdx)) { + addError(MatchStart.data(), "expected '+'/'-' for line offset, ':' " + "for column, or a buffer name"); + return 0; + } + Expected.TargetBufferID = SM.getIDForBufferIdentifier(TargetBufferName); + if (!Expected.TargetBufferID) { + addError(MatchStart.data(), + "no buffer with name '" + TargetBufferName + "' found"); + return 0; + } + if (MatchStart[0] != ':' || MatchStart[1] < '0' || MatchStart[1] > '9') { + addError(MatchStart.data(), + "expected absolute line number for diagnostic in other buffer"); + return 0; + } + } + StringRef Offs; + if (MatchStart[1] == '+') + Offs = MatchStart.slice(2, TextStartIdx).rtrim(); + else { + Offs = MatchStart.slice(1, TextStartIdx).rtrim(); + if (Offs[0] >= '0' && Offs[0] <= '9') + AbsoluteLine = true; + } - // Validate that earlier prefixes are not prefixes of alter - // prefixes... otherwise, we will never pattern match the later prefix. - validatePrefixList(AdditionalExpectedPrefixes); + size_t SpaceIndex = Offs.find(' '); + if (SpaceIndex != StringRef::npos && SpaceIndex < TextStartIdx) { + size_t Delta = Offs.size() - SpaceIndex; + MatchStart = MatchStart.substr(TextStartIdx - Delta); + TextStartIdx = Delta; + Offs = Offs.slice(0, SpaceIndex); + } else { + MatchStart = MatchStart.substr(TextStartIdx); + TextStartIdx = 0; + } - // Scan the memory buffer looking for expected-note/warning/error. - for (size_t Match = InputFile.find("expected-"); - Match != StringRef::npos; Match = InputFile.find("expected-", Match+1)) { - // Process this potential match. If we fail to process it, just move on to - // the next match. - StringRef MatchStart = InputFile.substr(Match); - const char *DiagnosticLoc = MatchStart.data(); - MatchStart = MatchStart.substr(strlen("expected-")); - - const char *ClassificationStartLoc = nullptr; - std::optional ExpectedClassification; - { - ExpectedCheckMatchStartParser parser(MatchStart); - // If we fail to parse... continue. - if (!parser.parse(AdditionalExpectedPrefixes)) { - continue; + size_t ColonIndex = Offs.find(':'); + // Check whether a line offset was provided + if (ColonIndex != 0) { + StringRef LineOffs = Offs.slice(0, ColonIndex); + if (LineOffs.getAsInteger(10, LineOffset)) { + addError(MatchStart.data(), "expected line offset before '{{'"); + return 0; } - MatchStart = parser.MatchStart; - ClassificationStartLoc = parser.ClassificationStartLoc; - ExpectedClassification = parser.ExpectedClassification; } - assert(ClassificationStartLoc); - assert(bool(ExpectedClassification)); - // Skip any whitespace before the {{. - MatchStart = MatchStart.substr(MatchStart.find_first_not_of(" \t")); - - size_t TextStartIdx = MatchStart.find("{{"); - if (TextStartIdx >= - MatchStart.find("\n")) { // Either not found, or found beyond next \n - addError(MatchStart.data(), - "expected {{ in expected-warning/note/error line"); - continue; + // Check whether a column was provided + if (ColonIndex != StringRef::npos) { + Offs = Offs.slice(ColonIndex + 1, Offs.size()); + int Column = 0; + if (Offs.getAsInteger(10, Column)) { + addError(MatchStart.data(), "expected column before '{{'"); + return 0; + } + Expected.ColumnNo = Column; } + } - ExpectedDiagnosticInfo Expected(DiagnosticLoc, ClassificationStartLoc, - /*ClassificationEndLoc=*/MatchStart.data(), - *ExpectedClassification); - int LineOffset = 0; + if (Expected.Classification == DiagnosticKindExpansion && !Expected.ColumnNo.has_value()) { + addError(DiagnosticLoc, "expected-expansion requires column location"); + return 0; + } - if (TextStartIdx > 0 && MatchStart[0] == '@') { - if (MatchStart[1] != '+' && MatchStart[1] != '-' && - MatchStart[1] != ':') { - addError(MatchStart.data(), - "expected '+'/'-' for line offset, or ':' for column"); - continue; + unsigned Count = 1; + if (TextStartIdx > 0) { + StringRef CountStr = MatchStart.substr(0, TextStartIdx).trim(" \t"); + if (CountStr == "*") { + Expected.mayAppear = true; + } else { + if (CountStr.getAsInteger(10, Count)) { + addError(MatchStart.data(), "expected match count before '{{'"); + return 0; } - StringRef Offs; - if (MatchStart[1] == '+') - Offs = MatchStart.slice(2, TextStartIdx).rtrim(); - else - Offs = MatchStart.slice(1, TextStartIdx).rtrim(); - - size_t SpaceIndex = Offs.find(' '); - if (SpaceIndex != StringRef::npos && SpaceIndex < TextStartIdx) { - size_t Delta = Offs.size() - SpaceIndex; - MatchStart = MatchStart.substr(TextStartIdx - Delta); - TextStartIdx = Delta; - Offs = Offs.slice(0, SpaceIndex); - } else { - MatchStart = MatchStart.substr(TextStartIdx); - TextStartIdx = 0; + if (Count == 0) { + addError(MatchStart.data(), + "expected positive match count before '{{'"); + return 0; } + } - size_t ColonIndex = Offs.find(':'); - // Check whether a line offset was provided - if (ColonIndex != 0) { - StringRef LineOffs = Offs.slice(0, ColonIndex); - if (LineOffs.getAsInteger(10, LineOffset)) { - addError(MatchStart.data(), "expected line offset before '{{'"); - continue; - } - } + // Resync up to the '{{'. + MatchStart = MatchStart.substr(TextStartIdx); + } - // Check whether a column was provided - if (ColonIndex != StringRef::npos) { - Offs = Offs.slice(ColonIndex + 1, Offs.size()); - int Column = 0; - if (Offs.getAsInteger(10, Column)) { - addError(MatchStart.data(), "expected column before '{{'"); - continue; - } - Expected.ColumnNo = Column; + size_t End = StringRef::npos; + if (Expected.Classification == DiagnosticKindExpansion) { + size_t NestedMatch = MatchStart.find("expected-"); + // Scan the memory buffer looking for expected-note/warning/error. + while (NestedMatch != StringRef::npos) { + StringRef NestedMatchStart = MatchStart.substr(NestedMatch); + ExpectedDiagnosticInfo NestedExpected(nullptr, nullptr, nullptr, + DiagnosticKind(-1)); + unsigned NestedCount = + parseExpectedDiagInfo(BufferID, NestedMatchStart, + PrevExpectedContinuationLine, NestedExpected); + + size_t PrevMatchEnd = NestedMatch + 1; + if (NestedCount > 0) { + // Add the diagnostic the expected number of times. + for (; NestedCount; --NestedCount) + Expected.NestedDiags.push_back(NestedExpected); + size_t NestedMatchEnd = + NestedExpected.ExpectedEnd - NestedMatchStart.data(); + assert(NestedMatchEnd > 0); + PrevMatchEnd = NestedMatch + NestedMatchEnd; } - } - unsigned Count = 1; - if (TextStartIdx > 0) { - StringRef CountStr = MatchStart.substr(0, TextStartIdx).trim(" \t"); - if (CountStr == "*") { - Expected.mayAppear = true; - } else { - if (CountStr.getAsInteger(10, Count)) { - addError(MatchStart.data(), "expected match count before '{{'"); - continue; - } - if (Count == 0) { - addError(MatchStart.data(), - "expected positive match count before '{{'"); - continue; - } + size_t NextEnd = MatchStart.find("}}", PrevMatchEnd); + NestedMatch = MatchStart.find("expected-", PrevMatchEnd); + if (NextEnd < NestedMatch) { + End = NextEnd; + break; } - - // Resync up to the '{{'. - MatchStart = MatchStart.substr(TextStartIdx); } - size_t End = MatchStart.find("}}"); if (End == StringRef::npos) { - addError(MatchStart.data(), + addError( + DiagnosticLoc, + "didn't find '}}' to match '{{' in expected-expansion"); + return 0; + } + if (Expected.NestedDiags.size() == 0) { + addError(DiagnosticLoc, "expected-expansion block is empty"); + // Keep going + } + } else { + End = MatchStart.find("}}"); + if (End == StringRef::npos) { + addError( + MatchStart.data(), "didn't find '}}' to match '{{' in expected-warning/note/error line"); - continue; + return 0; } + } - llvm::SmallString<256> Buf; - Expected.MessageRange = MatchStart.slice(2, End); - Expected.MessageStr = - Lexer::getEncodedStringSegment(Expected.MessageRange, Buf).str(); - if (PrevExpectedContinuationLine) - Expected.LineNo = PrevExpectedContinuationLine; - else - Expected.LineNo = SM.getLineAndColumnInBuffer( - BufferStartLoc.getAdvancedLoc(MatchStart.data() - - InputFile.data()), - BufferID) - .first; - Expected.LineNo += LineOffset; - - // Check if the next expected diagnostic should be in the same line. - StringRef AfterEnd = MatchStart.substr(End + strlen("}}")); - AfterEnd = AfterEnd.substr(AfterEnd.find_first_not_of(" \t")); - if (AfterEnd.starts_with("\\")) - PrevExpectedContinuationLine = Expected.LineNo; - else - PrevExpectedContinuationLine = 0; - - - // Scan for fix-its: {{10-14=replacement text}} - bool startNewAlternatives = true; - StringRef ExtraChecks = MatchStart.substr(End+2).ltrim(" \t"); - while (ExtraChecks.starts_with("{{")) { - // First make sure we have a closing "}}". - size_t EndIndex = ExtraChecks.find("}}"); - if (EndIndex == StringRef::npos) { - addError(ExtraChecks.data(), - "didn't find '}}' to match '{{' in diagnostic verification"); - break; - } - - // Allow for close braces to appear in the replacement text. - while (EndIndex + 2 < ExtraChecks.size() && - ExtraChecks[EndIndex + 2] == '}') - ++EndIndex; + llvm::SmallString<256> Buf; + Expected.MessageRange = MatchStart.slice(2, End); + Expected.MessageStr = + Lexer::getEncodedStringSegment(Expected.MessageRange, Buf).str(); + if (AbsoluteLine) + Expected.LineNo = 0; + else if (PrevExpectedContinuationLine) + Expected.LineNo = PrevExpectedContinuationLine; + else + Expected.LineNo = + SM.getLineAndColumnInBuffer(BufferStartLoc.getAdvancedLoc( + MatchStart.data() - InputFile.data()), + BufferID) + .first; + Expected.LineNo += LineOffset; + + // Check if the next expected diagnostic should be in the same line. + StringRef AfterEnd = MatchStart.substr(End + strlen("}}")); + AfterEnd = AfterEnd.substr(AfterEnd.find_first_not_of(" \t")); + if (AfterEnd.starts_with("\\")) + PrevExpectedContinuationLine = Expected.LineNo; + else + PrevExpectedContinuationLine = 0; + + // Scan for fix-its: {{10-14=replacement text}} + bool startNewAlternatives = true; + StringRef ExtraChecks = MatchStart.substr(End + 2).ltrim(" \t"); + while (ExtraChecks.starts_with("{{")) { + // First make sure we have a closing "}}". + size_t EndIndex = ExtraChecks.find("}}"); + if (EndIndex == StringRef::npos) { + addError(ExtraChecks.data(), + "didn't find '}}' to match '{{' in diagnostic verification"); + break; + } - const char *OpenLoc = ExtraChecks.data(); // Beginning of opening '{{'. - const char *CloseLoc = - ExtraChecks.data() + EndIndex + 2; // End of closing '}}'. + // Allow for close braces to appear in the replacement text. + while (EndIndex + 2 < ExtraChecks.size() && + ExtraChecks[EndIndex + 2] == '}') + ++EndIndex; - StringRef CheckStr = ExtraChecks.slice(2, EndIndex); - // Check for matching a later "}}" on a different line. - if (CheckStr.find_first_of("\r\n") != StringRef::npos) { - addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in " - "diagnostic verification"); - break; - } + const char *OpenLoc = ExtraChecks.data(); // Beginning of opening '{{'. + const char *CloseLoc = + ExtraChecks.data() + EndIndex + 2; // End of closing '}}'. - // Prepare for the next round of checks. - ExtraChecks = ExtraChecks.substr(EndIndex + 2).ltrim(" \t"); - - // Handle fix-it alternation. - // If two fix-its are separated by `||`, we can match either of the two. - // This is represented by putting them in the same subarray of `Fixits`. - // If they are not separated by `||`, we must match both of them. - // This is represented by putting them in separate subarrays of `Fixits`. - if (startNewAlternatives && - (Expected.Fixits.empty() || !Expected.Fixits.back().empty())) - Expected.Fixits.push_back({}); - - if (ExtraChecks.starts_with("||")) { - startNewAlternatives = false; - ExtraChecks = ExtraChecks.substr(2).ltrim(" \t"); - } else { - startNewAlternatives = true; - } + StringRef CheckStr = ExtraChecks.slice(2, EndIndex); + // Check for matching a later "}}" on a different line. + if (CheckStr.find_first_of("\r\n") != StringRef::npos) { + addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in " + "diagnostic verification"); + break; + } - // If this check starts with 'documentation-file=', check for a - // documentation file name instead of a fix-it. - if (CheckStr.starts_with(categoryDocFileSpecifier)) { - if (Expected.DocumentationFile.has_value()) { - addError(CheckStr.data(), - "each verified diagnostic may only have one " - "{{documentation-file=<#notes#>}} declaration"); - continue; - } + // Prepare for the next round of checks. + ExtraChecks = ExtraChecks.substr(EndIndex + 2).ltrim(" \t"); + + // Handle fix-it alternation. + // If two fix-its are separated by `||`, we can match either of the two. + // This is represented by putting them in the same subarray of `Fixits`. + // If they are not separated by `||`, we must match both of them. + // This is represented by putting them in separate subarrays of `Fixits`. + if (startNewAlternatives && + (Expected.Fixits.empty() || !Expected.Fixits.back().empty())) + Expected.Fixits.push_back({}); + + if (ExtraChecks.starts_with("||")) { + startNewAlternatives = false; + ExtraChecks = ExtraChecks.substr(2).ltrim(" \t"); + } else { + startNewAlternatives = true; + } - // Trim 'documentation-file='. - StringRef name = CheckStr.substr(categoryDocFileSpecifier.size()); - Expected.DocumentationFile = { OpenLoc, CloseLoc, name }; + // If this check starts with 'documentation-file=', check for a + // documentation file name instead of a fix-it. + if (CheckStr.starts_with(categoryDocFileSpecifier)) { + if (Expected.DocumentationFile.has_value()) { + addError(CheckStr.data(), + "each verified diagnostic may only have one " + "{{documentation-file=<#notes#>}} declaration"); continue; } - // This wasn't a documentation file specifier, so it must be a fix-it. - // Special case for specifying no fixits should appear. - if (CheckStr == fixitExpectationNoneString) { - if (Expected.noneMarkerStartLoc) { - addError(CheckStr.data() - 2, - Twine("A second {{") + fixitExpectationNoneString + - "}} was found. It may only appear once in an expectation."); - break; - } - - Expected.noneMarkerStartLoc = CheckStr.data() - 2; - continue; - } + // Trim 'documentation-file='. + StringRef name = CheckStr.substr(categoryDocFileSpecifier.size()); + Expected.DocumentationFile = {OpenLoc, CloseLoc, name}; + continue; + } + // This wasn't a documentation file specifier, so it must be a fix-it. + // Special case for specifying no fixits should appear. + if (CheckStr == fixitExpectationNoneString) { if (Expected.noneMarkerStartLoc) { - addError(Expected.noneMarkerStartLoc, Twine("{{") + - fixitExpectationNoneString + - "}} must be at the end."); + addError( + CheckStr.data() - 2, + Twine("A second {{") + fixitExpectationNoneString + + "}} was found. It may only appear once in an expectation."); break; } - if (CheckStr.empty()) { - addError(CheckStr.data(), Twine("expected fix-it verification within " - "braces; example: '1-2=text' or '") + - fixitExpectationNoneString + Twine("'")); - continue; - } + Expected.noneMarkerStartLoc = CheckStr.data() - 2; + continue; + } - // Parse the pieces of the fix-it. - ExpectedFixIt FixIt; - FixIt.StartLoc = OpenLoc; - FixIt.EndLoc = CloseLoc; + if (Expected.noneMarkerStartLoc) { + addError(Expected.noneMarkerStartLoc, Twine("{{") + + fixitExpectationNoneString + + "}} must be at the end."); + break; + } - if (const auto range = - parseExpectedFixItRange(CheckStr, Expected.LineNo, addError)) { - FixIt.Range = range.value(); - } else { - continue; - } + if (CheckStr.empty()) { + addError(CheckStr.data(), Twine("expected fix-it verification within " + "braces; example: '1-2=text' or '") + + fixitExpectationNoneString + Twine("'")); + continue; + } - if (!CheckStr.empty() && CheckStr.front() == '=') { - CheckStr = CheckStr.drop_front(); - } else { - addError(CheckStr.data(), - "expected '=' after range in fix-it verification"); - continue; - } + // Parse the pieces of the fix-it. + ExpectedFixIt FixIt; + FixIt.StartLoc = OpenLoc; + FixIt.EndLoc = CloseLoc; - // Translate literal "\\n" into '\n', inefficiently. - for (const char *current = CheckStr.begin(), *end = CheckStr.end(); - current != end; /* in loop */) { - if (*current == '\\' && current + 1 < end) { - if (current[1] == 'n') { - FixIt.Text += '\n'; - current += 2; - } else { // Handle \}, \\, etc. - FixIt.Text += current[1]; - current += 2; - } + if (const auto range = + parseExpectedFixItRange(CheckStr, Expected.LineNo)) { + FixIt.Range = range.value(); + } else { + continue; + } - } else { - FixIt.Text += *current++; + if (!CheckStr.empty() && CheckStr.front() == '=') { + CheckStr = CheckStr.drop_front(); + } else { + addError(CheckStr.data(), + "expected '=' after range in fix-it verification"); + continue; + } + + // Translate literal "\\n" into '\n', inefficiently. + for (const char *current = CheckStr.begin(), *end = CheckStr.end(); + current != end; + /* in loop */) { + if (*current == '\\' && current + 1 < end) { + if (current[1] == 'n') { + FixIt.Text += '\n'; + current += 2; + } else { // Handle \}, \\, etc. + FixIt.Text += current[1]; + current += 2; } + + } else { + FixIt.Text += *current++; } + } - Expected.Fixits.back().push_back(FixIt); + if (Expected.Classification == DiagnosticKindExpansion) { + addError(OpenLoc, "expected-expansion cannot have fixits"); } + Expected.Fixits.back().push_back(FixIt); + } - // If there's a trailing empty alternation, remove it. - if (!Expected.Fixits.empty() && Expected.Fixits.back().empty()) - Expected.Fixits.pop_back(); + // If there's a trailing empty alternation, remove it. + if (!Expected.Fixits.empty() && Expected.Fixits.back().empty()) + Expected.Fixits.pop_back(); - Expected.ExpectedEnd = ExtraChecks.data(); - - // Don't include trailing whitespace in the expected-foo{{}} range. - while (isspace(Expected.ExpectedEnd[-1])) - --Expected.ExpectedEnd; + Expected.ExpectedEnd = ExtraChecks.data(); - // Add the diagnostic the expected number of times. - for (; Count; --Count) - ExpectedDiagnostics.push_back(Expected); - } + // Don't include trailing whitespace in the expected-foo{{}} range. + while (isspace(Expected.ExpectedEnd[-1])) + --Expected.ExpectedEnd; + + return Count; +} +void DiagnosticVerifier::verifyDiagnostics(std::vector &ExpectedDiagnostics, unsigned BufferID) { // Make sure all the expected diagnostics appeared. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); @@ -913,9 +996,24 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { --i; auto &expected = ExpectedDiagnostics[i]; + unsigned ID = expected.TargetBufferID.value_or(BufferID); // Check to see if we had this expected diagnostic. + if (expected.Classification == DiagnosticKindExpansion) { + SourceLoc Loc = SM.getLocForLineCol(BufferID, expected.LineNo, *expected.ColumnNo); + if (Expansions.count(Loc) == 0) { + addError(expected.ExpectedStart, + "no expansion with diagnostics starting at " + + std::to_string(expected.LineNo) + ":" + std::to_string(*expected.ColumnNo)); + continue; + } + unsigned ExpansionBufferID = Expansions[Loc]; + verifyDiagnostics(expected.NestedDiags, ExpansionBufferID); + if (expected.NestedDiags.empty()) + ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); + continue; + } auto FoundDiagnosticInfo = - findDiagnostic(CapturedDiagnostics, expected, BufferID); + findDiagnostic(CapturedDiagnostics, expected, ID, SM); auto FoundDiagnosticIter = std::get<0>(FoundDiagnosticInfo); if (FoundDiagnosticIter == CapturedDiagnostics.end()) { // Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then @@ -928,8 +1026,8 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { auto emitFixItsError = [&](const char *location, const Twine &message, const char *replStartLoc, const char *replEndLoc, const std::string &replStr) { - llvm::SMFixIt fix(llvm::SMRange(SMLoc::getFromPointer(replStartLoc), - SMLoc::getFromPointer(replEndLoc)), + llvm::SMFixIt fix(llvm::SMRange(llvm::SMLoc::getFromPointer(replStartLoc), + llvm::SMLoc::getFromPointer(replEndLoc)), replStr); addError(location, message, fix); }; @@ -1070,8 +1168,8 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { // produce a fixit of our own. auto actual = renderDocumentationFile(FoundDiagnostic.CategoryDocFile); - auto replStartLoc = SMLoc::getFromPointer(expectedDocFile->StartLoc); - auto replEndLoc = SMLoc::getFromPointer(expectedDocFile->EndLoc); + auto replStartLoc = llvm::SMLoc::getFromPointer(expectedDocFile->StartLoc); + auto replEndLoc = llvm::SMLoc::getFromPointer(expectedDocFile->EndLoc); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(expectedDocFile->StartLoc, @@ -1093,53 +1191,17 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { else ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } - - // Check to see if we have any incorrect diagnostics. If so, diagnose them as - // such. - auto expectedDiagIter = ExpectedDiagnostics.begin(); - while (expectedDiagIter != ExpectedDiagnostics.end()) { - // Check to see if any found diagnostics have the right line and - // classification, but the wrong text. - auto I = CapturedDiagnostics.begin(); - for (auto E = CapturedDiagnostics.end(); I != E; ++I) { - // Verify the file and line of the diagnostic. - if (I->Line != expectedDiagIter->LineNo || I->SourceBufferID != BufferID - || I->Classification != expectedDiagIter->Classification) - continue; - - // Otherwise, we found it, break out. - break; - } +} - if (I == CapturedDiagnostics.end()) { - ++expectedDiagIter; +void DiagnosticVerifier::verifyRemaining( + std::vector &ExpectedDiagnostics, + const char *FileStart) { + std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); + for (auto &expected : ExpectedDiagnostics) { + if (expected.Classification == DiagnosticKindExpansion) { + verifyRemaining(expected.NestedDiags, FileStart); continue; } - - if (I->Message.find(expectedDiagIter->MessageStr) == StringRef::npos) { - auto StartLoc = - SMLoc::getFromPointer(expectedDiagIter->MessageRange.begin()); - auto EndLoc = SMLoc::getFromPointer(expectedDiagIter->MessageRange.end()); - - llvm::SMFixIt fixIt(llvm::SMRange{StartLoc, EndLoc}, I->Message); - addError(expectedDiagIter->MessageRange.begin(), - "incorrect message found", fixIt); - } else if (I->Column != *expectedDiagIter->ColumnNo) { - // The difference must be only in the column - addError(expectedDiagIter->MessageRange.begin(), - llvm::formatv("message found at column {0} but was expected to " - "appear at column {1}", - I->Column, *expectedDiagIter->ColumnNo)); - } else { - llvm_unreachable("unhandled difference from expected diagnostic"); - } - CapturedDiagnostics.erase(I); - expectedDiagIter = ExpectedDiagnostics.erase(expectedDiagIter); - } - - // Diagnose expected diagnostics that didn't appear. - std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); - for (auto const &expected : ExpectedDiagnostics) { std::string message = "expected "+getDiagKindString(expected.Classification) + " not produced"; @@ -1158,7 +1220,6 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { EndLoc = expected.ExpectedEnd; } else { // If we hit the end of line, then zap whitespace leading up to it. - auto FileStart = InputFile.data(); while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; @@ -1182,19 +1243,127 @@ DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { // Remove the expected-foo{{}} as a fixit. llvm::SMFixIt fixIt(llvm::SMRange{ - SMLoc::getFromPointer(StartLoc), - SMLoc::getFromPointer(EndLoc) + llvm::SMLoc::getFromPointer(StartLoc), + llvm::SMLoc::getFromPointer(EndLoc) }, ""); addError(expected.ExpectedStart, message, fixIt); } +} + +void DiagnosticVerifier::addError(const char *Loc, const Twine &message, + ArrayRef FixIts) { + auto loc = SourceLoc::getFromPointer(Loc); + auto diag = + SM.GetMessage(loc, llvm::SourceMgr::DK_Error, message, {}, FixIts); + Errors.push_back(diag); +} + +/// After the file has been processed, check to see if we got all of +/// the expected diagnostics and check to see if there were any unexpected +/// ones. +DiagnosticVerifier::Result DiagnosticVerifier::verifyFile(unsigned BufferID) { + Errors.clear(); + using llvm::SMLoc; + + StringRef InputFile = SM.getEntireTextForBuffer(BufferID); + + // Queue up all of the diagnostics, allowing us to sort them and emit them in + // file order. + + unsigned PrevExpectedContinuationLine = 0; + + std::vector ExpectedDiagnostics; + + // Validate that earlier prefixes are not prefixes of alter + // prefixes... otherwise, we will never pattern match the later prefix. + validatePrefixList(AdditionalExpectedPrefixes); + + const char *PrevMatchEnd = InputFile.data(); + // Scan the memory buffer looking for expected-note/warning/error. + for (size_t Match = InputFile.find("expected-"); + Match != StringRef::npos; Match = InputFile.find("expected-", Match+1)) { + // Process this potential match. If we fail to process it, just move on to + // the next match. + StringRef MatchStart = InputFile.substr(Match); + if (MatchStart.data() < PrevMatchEnd) + continue; + ExpectedDiagnosticInfo Expected(nullptr, nullptr, nullptr, DiagnosticKind(-1)); + unsigned Count = parseExpectedDiagInfo(BufferID, MatchStart, PrevExpectedContinuationLine, Expected); + if (Count < 1) + continue; + + // Add the diagnostic the expected number of times. + for (; Count; --Count) + ExpectedDiagnostics.push_back(Expected); + PrevMatchEnd = Expected.ExpectedEnd; + } + + verifyDiagnostics(ExpectedDiagnostics, BufferID); + + // Check to see if we have any incorrect diagnostics. If so, diagnose them as + // such. + auto expectedDiagIter = ExpectedDiagnostics.begin(); + while (expectedDiagIter != ExpectedDiagnostics.end()) { + // Check to see if any found diagnostics have the right line and + // classification, but the wrong text. + auto I = CapturedDiagnostics.begin(); + for (auto E = CapturedDiagnostics.end(); I != E; ++I) { + // Verify the file and line of the diagnostic. + if (I->Line != expectedDiagIter->LineNo || I->SourceBufferID != BufferID + || I->Classification != expectedDiagIter->Classification) + continue; + + // Otherwise, we found it, break out. + break; + } + + if (I == CapturedDiagnostics.end()) { + ++expectedDiagIter; + continue; + } + + if (I->Message.find(expectedDiagIter->MessageStr) == StringRef::npos) { + auto StartLoc = + SMLoc::getFromPointer(expectedDiagIter->MessageRange.begin()); + auto EndLoc = SMLoc::getFromPointer(expectedDiagIter->MessageRange.end()); + + llvm::SMFixIt fixIt(llvm::SMRange{StartLoc, EndLoc}, I->Message); + addError(expectedDiagIter->MessageRange.begin(), + "incorrect message found", fixIt); + } else if (I->Column != *expectedDiagIter->ColumnNo) { + // The difference must be only in the column + addError(expectedDiagIter->MessageRange.begin(), + llvm::formatv("message found at column {0} but was expected to " + "appear at column {1}", + I->Column, *expectedDiagIter->ColumnNo)); + } else { + llvm_unreachable("unhandled difference from expected diagnostic"); + } + CapturedDiagnostics.erase(I); + expectedDiagIter = ExpectedDiagnostics.erase(expectedDiagIter); + } + + // Diagnose expected diagnostics that didn't appear. + verifyRemaining(ExpectedDiagnostics, InputFile.data()); // Verify that there are no diagnostics (in MemoryBuffer) left in the list. bool HadUnexpectedDiag = false; auto CapturedDiagIter = CapturedDiagnostics.begin(); while (CapturedDiagIter != CapturedDiagnostics.end()) { if (CapturedDiagIter->SourceBufferID != BufferID) { - ++CapturedDiagIter; - continue; + if (!CapturedDiagIter->SourceBufferID) { + ++CapturedDiagIter; + continue; + } + + // Diagnostics attached to generated sources originating in this + // buffer also count as part of this buffer for this purpose. + const GeneratedSourceInfo *GSI = + SM.getGeneratedSourceInfo(CapturedDiagIter->SourceBufferID.value()); + if (!GSI || llvm::find(GSI->ancestors, BufferID) == GSI->ancestors.end()) { + ++CapturedDiagIter; + continue; + } } HadUnexpectedDiag = true; @@ -1255,6 +1424,27 @@ void DiagnosticVerifier::printRemainingDiagnostics() const { } } +static void +processExpansions(SourceManager &SM, llvm::DenseMap &Expansions, + std::vector &CapturedDiagnostics) { + for (auto &diag : CapturedDiagnostics) { + if (!diag.SourceBufferID.has_value()) + continue; + const GeneratedSourceInfo *GSI = + SM.getGeneratedSourceInfo(diag.SourceBufferID.value()); + if (!GSI) + continue; + SourceLoc ExpansionStart = GSI->originalSourceRange.getStart(); + if (ExpansionStart.isInvalid()) + continue; + if (Expansions.count(ExpansionStart)) { + ASSERT(Expansions[ExpansionStart] == diag.SourceBufferID.value()); + continue; + } + Expansions.insert(std::make_pair(ExpansionStart, diag.SourceBufferID.value())); + } +} + //===----------------------------------------------------------------------===// // Main entrypoints //===----------------------------------------------------------------------===// @@ -1309,6 +1499,8 @@ bool DiagnosticVerifier::finishProcessing() { } } + processExpansions(SM, Expansions, CapturedDiagnostics); + ArrayRef BufferIDLists[2] = { BufferIDs, additionalBufferIDs }; for (ArrayRef BufferIDList : BufferIDLists) for (auto &BufferID : BufferIDList) { diff --git a/test/Concurrency/task_local.swift b/test/Concurrency/task_local.swift index d7818271ef4a5..12b6765632f6f 100644 --- a/test/Concurrency/task_local.swift +++ b/test/Concurrency/task_local.swift @@ -7,6 +7,11 @@ struct TL { @TaskLocal // expected-note{{in expansion of macro 'TaskLocal' on static property 'number' here}} static var number: Int = 0 + /* + expected-expansion@-2:29{{ + expected-note@1:8{{change 'let' to 'var' to make it mutable}} + }} + */ @TaskLocal static var someNil: Int? @@ -14,6 +19,11 @@ struct TL { // expected-note@+1{{in expansion of macro 'TaskLocal' on static property 'noValue' here}} @TaskLocal // expected-error{{@TaskLocal' property must have default value, or be optional}} static var noValue: Int // expected-note{{'noValue' declared here}} + /* + expected-expansion@-2:26{{ + expected-error@3:9{{cannot find '$noValue' in scope; did you mean 'noValue'?}} + }} + */ @TaskLocal // expected-error{{'@TaskLocal' can only be applied to 'static' property}} var notStatic: String? diff --git a/test/Distributed/Macros/distributed_macro_expansion_DistributedProtocol_errors.swift b/test/Distributed/Macros/distributed_macro_expansion_DistributedProtocol_errors.swift index 9d776369a5c47..8759d4c906d67 100644 --- a/test/Distributed/Macros/distributed_macro_expansion_DistributedProtocol_errors.swift +++ b/test/Distributed/Macros/distributed_macro_expansion_DistributedProtocol_errors.swift @@ -30,6 +30,14 @@ distributed actor Caplin { protocol Fail: DistributedActor { distributed func method() -> String } +/* +expected-expansion@-2:2{{ + expected-error@1:19{{distributed actor '$Fail' does not declare ActorSystem it can be used with}} + expected-note@1:13{{you can provide a module-wide default actor system by declaring:}} + expected-error@1:19{{type '$Fail' does not conform to protocol 'DistributedActor'}} + expected-note@1:19{{add stubs for conformance}} +}} +*/ @Resolvable // expected-note2{{in expansion of macro 'Resolvable' on protocol 'SomeRoot' here}} public protocol SomeRoot: DistributedActor, Sendable @@ -39,3 +47,9 @@ public protocol SomeRoot: DistributedActor, Sendable static var staticValue: String { get } var value: String { get } } +/* +expected-expansion@-2:2{{ + expected-error@1:27{{type '$SomeRoot' does not conform to protocol 'SomeRoot'}} + expected-note@1:27{{add stubs for conformance}} +}} +*/ diff --git a/test/Macros/Inputs/syntax_macro_definitions.swift b/test/Macros/Inputs/syntax_macro_definitions.swift index 7eee73fb6ca2b..f465023805591 100644 --- a/test/Macros/Inputs/syntax_macro_definitions.swift +++ b/test/Macros/Inputs/syntax_macro_definitions.swift @@ -2051,7 +2051,7 @@ public struct DefineAnonymousTypesMacro: DeclarationMacro { results += [""" - struct \(context.makeUniqueName("name")) where T == Equatable { // expect error: need 'any' + struct \(context.makeUniqueName("name")) where T == Equatable { // expected-warning{{must be written 'any Hashable'}} #introduceTypeCheckingErrors // make sure we get nested errors } """] @@ -2070,7 +2070,7 @@ public struct IntroduceTypeCheckingErrorsMacro: DeclarationMacro { """ struct \(context.makeUniqueName("name")) { - struct \(context.makeUniqueName("name")) where T == Hashable { // expect error: need 'any' + struct \(context.makeUniqueName("name")) where T == Hashable { // expected-warning{{must be written 'any Hashable'}} } } """ diff --git a/test/Macros/Inputs/top_level_freestanding_other.swift b/test/Macros/Inputs/top_level_freestanding_other.swift index c4a296a34fee5..7c3ac0214f21c 100644 --- a/test/Macros/Inputs/top_level_freestanding_other.swift +++ b/test/Macros/Inputs/top_level_freestanding_other.swift @@ -13,7 +13,14 @@ func deprecated() -> Int { 0 } var globalVar3 = #stringify({ deprecated() }) // expected-note@-1 {{in expansion of macro 'stringify' here}} // expected-warning@-2{{'deprecated()' is deprecated}} +// expected-expansion@-3:18{{ +// expected-warning@2:9{{'deprecated()' is deprecated}} +// }} var globalVar4 = #stringify({ deprecated() }) // expected-note@-1 {{in expansion of macro 'stringify' here}} // expected-warning@-2{{'deprecated()' is deprecated}} +// expected-expansion@-3:18{{ +// expected-warning@2:9{{'deprecated()' is deprecated}} +// }} + diff --git a/test/Macros/SwiftifyImport/MacroErrors/UnexpectedCountType.swift b/test/Macros/SwiftifyImport/MacroErrors/UnexpectedCountType.swift index 5042895b4b2a3..1b37bf45bd7cb 100644 --- a/test/Macros/SwiftifyImport/MacroErrors/UnexpectedCountType.swift +++ b/test/Macros/SwiftifyImport/MacroErrors/UnexpectedCountType.swift @@ -1,17 +1,23 @@ -// REQUIRES: swift_swift_parser - -// XFAIL: * - -// RUN: not %target-swift-frontend %s -swift-version 5 -module-name main -disable-availability-checking -typecheck -plugin-path %swift-plugin-dir -dump-macro-expansions 2>&1 | %FileCheck --match-full-lines %s -// RUN: %target-typecheck-verify-swift %s -swift-version 5 -module-name main -disable-availability-checking -typecheck -plugin-path %swift-plugin-dir -verify - +//--- test.swift @_SwiftifyImport(.countedBy(pointer: .param(1), count: "len")) func myFunc(_ ptr: UnsafePointer, _ len: String) { } +// expected-note@-3 2{{in expansion of macro '_SwiftifyImport' on global function 'myFunc' here}} + +// expected-error@@__swiftmacro_4main6myFunc15_SwiftifyImportfMp_.swift:4:15{{no exact matches in call to initializer}} +// expected-error@@__swiftmacro_4main6myFunc15_SwiftifyImportfMp_.swift:4:48{{cannot force unwrap value of non-optional type 'String'}} -// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload -// CHECK-NEXT: func myFunc(_ ptr: UnsafeBufferPointer) { -// CHECK-NEXT: myFunc(ptr.baseAddress!, String(exactly: ptr.count)!) -// CHECK-NEXT: } +// REQUIRES: swift_swift_parser +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %target-swift-frontend %t/test.swift -swift-version 5 -module-name main -disable-availability-checking -typecheck -plugin-path %swift-plugin-dir -dump-macro-expansions -verify 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace -// expected-error@_SwiftifyImport:2{{no exact matches in call to initializer}} +// CHECK:@__swiftmacro_4main6myFunc15_SwiftifyImportfMp_.swift +// CHECK-NEXT:------------------------------ +// CHECK-NEXT:/// This is an auto-generated wrapper for safer interop +// CHECK-NEXT:@_alwaysEmitIntoClient @_disfavoredOverload +// CHECK-NEXT:func myFunc(_ ptr: UnsafeBufferPointer) { +// CHECK-NEXT: let len = String(exactly: unsafe ptr.count)! +// CHECK-NEXT: return unsafe myFunc(ptr.baseAddress!, len) +// CHECK-NEXT:} +// CHECK-NEXT:------------------------------ diff --git a/test/Macros/accessor_macros.swift b/test/Macros/accessor_macros.swift index e9da34f84fa0e..df722c8d535d8 100644 --- a/test/Macros/accessor_macros.swift +++ b/test/Macros/accessor_macros.swift @@ -99,6 +99,11 @@ struct MyBrokenStruct { // expected-note@+1 2{{in expansion of macro 'myPropertyWrapper' on property 'birthDate' here}} @myPropertyWrapper var birthDate: Date? { + /* + expected-expansion@-2:25{{ + expected-error@1:1{{variable already has a getter}} + }} + */ // CHECK-DIAGS: variable already has a getter // CHECK-DIAGS: in expansion of macro // CHECK-DIAGS: previous definition of getter here @@ -153,6 +158,12 @@ struct HasStoredTests { // expected-error@-1{{expansion of macro 'MakeComputedSneakily()' produced an unexpected getter}} // expected-note@-2 2{{in expansion of macro}} // expected-note@-3 2{{'z' declared here}} + /* + expected-expansion@-5:36{{ + expected-error@3:9{{cannot find '_z' in scope; did you mean 'z'?}} + expected-error@6:9{{cannot find '_z' in scope; did you mean 'z'?}} + }} + */ #endif } diff --git a/test/Macros/macro_attribute_expansiondecl.swift b/test/Macros/macro_attribute_expansiondecl.swift index 1c07a032c7d06..132f155e136d2 100644 --- a/test/Macros/macro_attribute_expansiondecl.swift +++ b/test/Macros/macro_attribute_expansiondecl.swift @@ -160,10 +160,19 @@ struct S1 { // FIXME: Diagnostics could be better. struct S2 { // expected-note 4 {{add '@available' attribute to enclosing struct}} - // expected-note@+3 6 {{in expansion of macro 'funcFromClosureMacro' here}} // expected-error@+2 {{'APIFrom99()' is only available in macOS 99 or newer}} - // expected-error@+2 {{'APIFrom99()' is only available in macOS 99 or newer}} expected-note@+2 {{add 'if #available' version check}} + // expected-error@+12 {{'APIFrom99()' is only available in macOS 99 or newer}} expected-note@+12 {{add 'if #available' version check}} #funcFromClosureMacro(APIFrom99()) { + /* + expected-note@-2 6 {{in expansion of macro 'funcFromClosureMacro' here}} + expected-expansion@-3:3{{ + expected-note@1:6 2{{add '@available' attribute to enclosing instance method}} + expected-error@2:9{{'APIFrom99()' is only available in macOS 99 or newer}} + expected-note@2:9{{add 'if #available' version check}} + expected-error@14:11{{'APIFrom99()' is only available in macOS 99 or newer}} + expected-note@14:11{{add 'if #available' version check}} + }} + */ _ = APIFrom99() if #available(macOS 999, *) { _ = APIFrom99() diff --git a/test/Macros/macro_expand.swift b/test/Macros/macro_expand.swift index 074fcb5a6bd54..5480b735b035d 100644 --- a/test/Macros/macro_expand.swift +++ b/test/Macros/macro_expand.swift @@ -73,11 +73,11 @@ macro NotCovered() = #externalMacro(module: "MacroDefinition", type: "InvalidMac struct MemberNotCovered { #NotCovered // expected-note@-1 {{in expansion of macro 'NotCovered' here}} - - // CHECK-DIAGS: error: declaration name 'value' is not covered by macro 'NotCovered' - // CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-5]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll10NotCoveredfMf_.swift - // CHECK-DIAGS: var value: Int - // CHECK-DIAGS: END CONTENTS OF FILE + /* + expected-expansion@-3:3 {{ + expected-error@1:5{{declaration name 'value' is not covered by macro 'NotCovered'}} + }} + */ } @attached(peer) @@ -86,24 +86,29 @@ macro Invalid() = #externalMacro(module: "MacroDefinition", type: "InvalidMacro" @Invalid struct Bad {} // expected-note@-2 18 {{in expansion of macro 'Invalid' on struct 'Bad' here}} +/* +expected-expansion@-3:14 {{ + expected-error@1:8{{macro expansion cannot introduce import}} + expected-error@3:17{{macro expansion cannot introduce precedence group}} + expected-error@6:25{{macro 'myMacro()' requires a definition}} + expected-error@6:25{{macro expansion cannot introduce macro}} + expected-error@8:1{{macro expansion cannot introduce extension}} + expected-error@11:1{{macro expansion cannot introduce '@main' type}} + expected-error@12:8{{declaration name 'MyMain' is not covered by macro 'Invalid'}} + expected-error@17:11{{declaration name 'Array' is not covered by macro 'Invalid'}} + expected-error@19:11{{declaration name 'Dictionary' is not covered by macro 'Invalid'}} + expected-error@21:11{{macro expansion cannot introduce default literal type 'BooleanLiteralType'}} + expected-error@23:11{{macro expansion cannot introduce default literal type 'ExtendedGraphemeClusterType'}} + expected-error@25:11{{macro expansion cannot introduce default literal type 'FloatLiteralType'}} + expected-error@27:11{{macro expansion cannot introduce default literal type 'IntegerLiteralType'}} + expected-error@29:11{{macro expansion cannot introduce default literal type 'StringLiteralType'}} + expected-error@31:11{{macro expansion cannot introduce default literal type 'UnicodeScalarType'}} + expected-error@33:11{{macro expansion cannot introduce default literal type '_ColorLiteralType'}} + expected-error@35:11{{macro expansion cannot introduce default literal type '_ImageLiteralType'}} + expected-error@37:11{{macro expansion cannot introduce default literal type '_FileReferenceLiteralType'}} +}} +*/ -// CHECK-DIAGS: error: macro expansion cannot introduce import -// CHECK-DIAGS: error: macro expansion cannot introduce precedence group -// CHECK-DIAGS: error: macro expansion cannot introduce macro -// CHECK-DIAGS: error: macro expansion cannot introduce extension -// CHECK-DIAGS: error: macro expansion cannot introduce '@main' type -// CHECK-DIAGS: error: declaration name 'MyMain' is not covered by macro 'Invalid' -// CHECK-DIAGS: error: declaration name 'Array' is not covered by macro 'Invalid' -// CHECK-DIAGS: error: declaration name 'Dictionary' is not covered by macro 'Invalid' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type 'BooleanLiteralType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type 'ExtendedGraphemeClusterType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type 'FloatLiteralType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type 'IntegerLiteralType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type 'StringLiteralType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type 'UnicodeScalarType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type '_ColorLiteralType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type '_ImageLiteralType' -// CHECK-DIAGS: error: macro expansion cannot introduce default literal type '_FileReferenceLiteralType' // CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser3Bad7InvalidfMp_.swift // CHECK-DIAGS: import Swift @@ -132,21 +137,28 @@ struct Bad {} class HasStoredPropertyClassInvalid { #AddStoredProperty((Self.self, 0).1) // expected-note {{in expansion of macro 'AddStoredProperty' here}} - // CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-2]]_2_33_{{.*}}AddStoredPropertyfMf_.swift:1:22: error: covariant 'Self' type cannot be referenced from a stored property initializer + /* + expected-expansion@-2:3 {{ + expected-error@1:22{{covariant 'Self' type cannot be referenced from a stored property initializer}} + }} + */ } // Redeclaration checking should behave as though expansions are part of the // source file. struct RedeclChecking { #varValue + /* + expected-expansion@-2:3 {{ + expected-note@1:5{{'value' previously declared here}} + }} + */ // expected-error@+1 {{invalid redeclaration of 'value'}} var value: Int { 0 } } -// CHECK-DIAGS: macro_expand.swift:[[@LINE-3]]:7: error: invalid redeclaration of 'value' -// CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-8]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll8varValuefMf_.swift:1:5: note: 'value' previously declared here -// CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-9]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll8varValuefMf_.swift: +// CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-12]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll8varValuefMf_.swift: // CHECK-DIAGS: var value: Int { // CHECK-DIAGS: 1 // CHECK-DIAGS: } @@ -159,11 +171,19 @@ public macro ThrowCancellation() = #externalMacro(module: "MacroDefinition", typ // error mismatch. @ThrowCancellation // expected-note {{in expansion of macro 'ThrowCancellation' on global function 'issue79039()' here}} func issue79039() throws(DecodingError) -// CHECK-DIAGS: @__swiftmacro_9MacroUser10issue7903917ThrowCancellationfMb_.swift:2:11: error: thrown expression type 'CancellationError' cannot be converted to error type 'DecodingError' +/* +expected-expansion@-2:39 {{ + expected-error@2:11{{thrown expression type 'CancellationError' cannot be converted to error type 'DecodingError'}} +}} +*/ @ThrowCancellation // expected-note {{in expansion of macro 'ThrowCancellation' on global function 'issue79039_2()' here}} func issue79039_2() throws(DecodingError) {} -// CHECK-DIAGS: @__swiftmacro_9MacroUser12issue79039_217ThrowCancellationfMb_.swift:2:11: error: thrown expression type 'CancellationError' cannot be converted to error type 'DecodingError' +/* +expected-expansion@-2:43 {{ + expected-error@2:11{{thrown expression type 'CancellationError' cannot be converted to error type 'DecodingError'}} +}} +*/ #endif @freestanding(declaration) @@ -176,16 +196,28 @@ macro AccidentalCodeItem() = #externalMacro(module: "MacroDefinition", type: "Fa func invalidDeclarationMacro() { #accidentalCodeItem // expected-note@-1 {{in expansion of macro 'accidentalCodeItem' here}} - // CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-3]]_2_18accidentalCodeItemfMf_.swift:1:1: error: expected macro expansion to produce a declaration + /* + expected-expansion@-3:3 {{ + expected-error@1:1{{expected macro expansion to produce a declaration}} + }} + */ @AccidentalCodeItem struct S {} // expected-note@-1 {{in expansion of macro 'AccidentalCodeItem' on struct 'S' here}} - // CHECK-DIAGS: @__swiftmacro_9MacroUser018invalidDeclarationA0yyF5S_$l018AccidentalCodeItemfMp_.swift:1:1: error: expected macro expansion to produce a declaration + /* + expected-expansion@-3:34 {{ + expected-error@1:1{{expected macro expansion to produce a declaration}} + }} + */ do { @AccidentalCodeItem struct S {} // expected-note@-1 {{in expansion of macro 'AccidentalCodeItem' on struct 'S' here}} - // CHECK-DIAGS: @__swiftmacro_9MacroUser018invalidDeclarationA0yyF5S_$l118AccidentalCodeItemfMp_.swift:1:1: error: expected macro expansion to produce a declaration + /* + expected-expansion@-3:36 {{ + expected-error@1:1{{expected macro expansion to produce a declaration}} + }} + */ } } #endif @@ -323,9 +355,14 @@ func testNested() { struct Nested { } _ = #stringify(#assertAny(Nested())) // expected-note@-1 {{in expansion of macro 'stringify' here}} -// CHECK-DIAGS-NOT: error: cannot convert value of type 'Nested' to expected argument type 'Bool' -// CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX{{.*}}_9stringifyfMf_9assertAnyfMf_.swift:1:8: error: cannot convert value of type 'Nested' to expected argument type 'Bool' -// CHECK-DIAGS-NOT: error: cannot convert value of type 'Nested' to expected argument type 'Bool' + /* + expected-expansion@-3:7 {{ + expected-note@1:2{{in expansion of macro 'assertAny' here}} + expected-expansion@1:2{{ + expected-error@1:8{{cannot convert value of type 'Nested' to expected argument type 'Bool'}} + }} + }} + */ // PRETTY-DIAGS: 1:8: error: cannot convert value of type 'Nested' to expected argument type 'Bool' // PRETTY-DIAGS: macro_expand.swift:{{.*}}:39: note: expanded code originates here @@ -344,8 +381,15 @@ func testStringifyWithThrows() throws { #if TEST_DIAGNOSTICS // FIXME: Lots of duplicate notes here _ = #stringify(maybeThrowing()) // expected-note 4{{in expansion of macro 'stringify' here}} + /* + expected-expansion@-2:7 {{ + expected-error@1:2{{call can throw but is not marked with 'try'}} + expected-note@1:2{{did you mean to disable error propagation?}} + expected-note@1:2{{did you mean to handle error as optional value?}} + expected-note@1:2{{did you mean to use 'try'?}} + }} + */ - // CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX{{.*}}_9stringifyfMf1_.swift:1:2: error: call can throw but is not marked with 'try' #endif // The macro adds the 'try' for us. @@ -385,14 +429,18 @@ func testAddBlocker(a: Int, b: Int, c: Int, oa: OnlyAdds) { _ = #addBlocker(oa + oa) // expected-error{{blocked an add; did you mean to subtract? (from macro 'addBlocker')}} // expected-note@-1{{in expansion of macro 'addBlocker' here}} // expected-note@-2{{use '-'}}{{22-23=-}} - - // CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX{{.*}}_10addBlockerfMf1_.swift:1:4: error: binary operator '-' cannot be applied to two 'OnlyAdds' operands [] [] - // CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX{{.*}}_10addBlockerfMf1_.swift: - // CHECK-DIAGS-NEXT: Original source range: {{.*}}macro_expand.swift:[[@LINE-6]]:7 - {{.*}}macro_expand.swift:[[@LINE-6]]:27 - // CHECK-DIAGS-NEXT: oa - oa - // CHECK-DIAGS-NEXT: END CONTENTS OF FILE + /* + expected-expansion@-4:7 {{ + expected-error@1:4{{binary operator '-' cannot be applied to two 'OnlyAdds' operands}} + }} + */ _ = #addBlocker({ // expected-note{{in expansion of macro 'addBlocker' here}} + /* + expected-expansion@-2:7 {{ + expected-error@9:16{{referencing operator function '-' on 'FloatingPoint' requires that 'OnlyAdds' conform to 'FloatingPoint'}} + }} + */ print("hello") print(oa + oa) // expected-error{{blocked an add; did you mean to subtract? (from macro 'addBlocker')}} @@ -403,7 +451,13 @@ func testAddBlocker(a: Int, b: Int, c: Int, oa: OnlyAdds) { // Check recursion. #recurse(false) // okay - #recurse(true) // expected-note{{in expansion of macro 'recurse' here}} + #recurse(true) + /* + expected-expansion@-2:3 {{ + expected-error@1:1{{recursive expansion of macro 'recurse'}} + }} + expected-note@-5{{in expansion of macro 'recurse' here}} + */ #endif } @@ -494,6 +548,14 @@ func testFreestandingMacroExpansion() { struct Foo3 { #bitwidthNumberedStructs("BUG", blah: false) // expected-note@-1 4{{in expansion of macro 'bitwidthNumberedStructs' here}} + /* + expected-expansion@-3:5 {{ + expected-error@3:14{{unexpected non-void return value in void function}} + expected-note@3:14{{did you mean to add a return type?}} + expected-error@6:14{{unexpected non-void return value in void function}} + expected-note@6:14{{did you mean to add a return type?}} + }} + */ // CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX{{.*}}_23bitwidthNumberedStructsfMf_.swift // CHECK-DIAGS: struct BUG { // CHECK-DIAGS: func $s9MacroUser0023macro_expandswift_elFCffMX{{.*}}_23bitwidthNumberedStructsfMf_6methodfMu_() @@ -727,6 +789,11 @@ struct ABIAttrWithFreestandingMacro1 { @abi(#varValue) #varValue // expected-note@-1 {{in expansion of macro 'varValue' here}} + /* + expected-expansion@-3:3 {{ + expected-error@2:6{{cannot use pound literal in '@abi'}} + }} + */ } struct ABIAttrWithFreestandingMacro2 { @@ -759,7 +826,11 @@ func invalidDeclarationMacro2() { func f() { #accidentalCodeItem // expected-note@-1 {{in expansion of macro 'accidentalCodeItem' here}} - // CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-3]]_6_18accidentalCodeItemfMf_.swift:1:1: error: expected macro expansion to produce a declaration + /* + expected-expansion@-3:7 {{ + expected-error@1:1{{expected macro expansion to produce a declaration}} + }} + */ } } } diff --git a/test/Macros/macro_expand_extensions.swift b/test/Macros/macro_expand_extensions.swift index 7196eea12465a..0ee4e20d0e1d9 100644 --- a/test/Macros/macro_expand_extensions.swift +++ b/test/Macros/macro_expand_extensions.swift @@ -10,9 +10,6 @@ // RUN: %FileCheck -check-prefix=CHECK-DUMP %s < %t/expansions-dump.txt // RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5 -I %t -// RUN: not %target-swift-frontend -swift-version 5 -typecheck -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -serialize-diagnostics-path %t/macro_expand.dia %s -emit-macro-expansion-files no-diagnostics -// RUN: c-index-test -read-diagnostics %t/macro_expand.dia 2>&1 | %FileCheck -check-prefix CHECK-DIAGS %s - // Ensure that we can serialize this file as a module. // RUN: %target-swift-frontend -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -I %t -disable-availability-checking -emit-module -o %t/MyModule.swiftmodule -enable-testing @@ -137,8 +134,11 @@ macro UndocumentedNamesInExtension() = #externalMacro(module: "MacroDefinition", @UndocumentedNamesInExtension struct S {} // expected-note@-2 {{in expansion of macro 'UndocumentedNamesInExtension' on generic struct 'S' here}} - -// CHECK-DIAGS: error: declaration name 'requirement()' is not covered by macro 'UndocumentedNamesInExtension' +/* +expected-expansion@-3:21 {{ + expected-error@2:15{{declaration name 'requirement()' is not covered by macro 'UndocumentedNamesInExtension'}} +}} +*/ @attached(extension, names: named(requirement)) macro UndocumentedConformanceInExtension() = #externalMacro(module: "MacroDefinition", type: "AlwaysAddConformance") @@ -146,8 +146,11 @@ macro UndocumentedConformanceInExtension() = #externalMacro(module: "MacroDefini @UndocumentedConformanceInExtension struct InvalidConformance {} // expected-note@-2 {{in expansion of macro 'UndocumentedConformanceInExtension' on generic struct 'InvalidConformance' here}} - -// CHECK-DIAGS: error: conformance to 'P' is not covered by macro 'UndocumentedConformanceInExtension' +/* +expected-expansion@-3:38 {{ + expected-error@1:1{{conformance to 'P' is not covered by macro 'UndocumentedConformanceInExtension'}} +}} +*/ @attached(extension) macro UndocumentedCodable() = #externalMacro(module: "MacroDefinition", type: "AlwaysAddCodable") @@ -155,8 +158,11 @@ macro UndocumentedCodable() = #externalMacro(module: "MacroDefinition", type: "A @UndocumentedCodable struct TestUndocumentedCodable {} // expected-note@-2 {{in expansion of macro 'UndocumentedCodable' on struct 'TestUndocumentedCodable' here}} - -// CHECK-DIAGS: error: conformance to 'Codable' (aka 'Decodable & Encodable') is not covered by macro 'UndocumentedCodable' +/* +expected-expansion@-3:34 {{ + expected-error@1:1{{conformance to 'Codable' (aka 'Decodable & Encodable') is not covered by macro 'UndocumentedCodable'}} +}} +*/ @attached(extension, conformances: Decodable) macro UndocumentedEncodable() = #externalMacro(module: "MacroDefinition", type: "AlwaysAddCodable") @@ -164,8 +170,11 @@ macro UndocumentedEncodable() = #externalMacro(module: "MacroDefinition", type: @UndocumentedEncodable struct TestUndocumentedEncodable {} // expected-note@-2 {{in expansion of macro 'UndocumentedEncodable' on struct 'TestUndocumentedEncodable' here}} - -// CHECK-DIAGS: error: conformance to 'Codable' (aka 'Decodable & Encodable') is not covered by macro 'UndocumentedEncodable' +/* +expected-expansion@-3:36 {{ + expected-error@1:1{{conformance to 'Codable' (aka 'Decodable & Encodable') is not covered by macro 'UndocumentedEncodable'}} +}} +*/ @attached(extension) macro BadExtension() = #externalMacro(module: "MacroDefinition", type: "BadExtensionMacro") @@ -176,7 +185,11 @@ struct HasSomeNestedType { @BadExtension // expected-note {{in expansion of macro 'BadExtension' on struct 'SomeNestedType' here}} struct SomeNestedType {} } -// CHECK-DIAGS: error: cannot find type 'SomeNestedType' in scope +/* +expected-expansion@-2:2 {{ + expected-error@1:11{{cannot find type 'SomeNestedType' in scope}} +}} +*/ #endif diff --git a/test/Macros/macro_expand_other.swift b/test/Macros/macro_expand_other.swift index 4d210deb76d8c..b215e1d2effe3 100644 --- a/test/Macros/macro_expand_other.swift +++ b/test/Macros/macro_expand_other.swift @@ -32,7 +32,15 @@ func testFreestandingExpansionOfOther() { #if TEST_DIAGNOSTICS #recurseThrough(true) - // expected-note@-1 {{in expansion of macro 'recurseThrough' here}} + /* + expected-expansion@-2:1{{ + expected-expansion@1:1{{ + expected-error@1:1{{recursive expansion of macro 'recurse'}} + }} + expected-note@1:1{{in expansion of macro 'recurse' here}} + }} + expected-note@-8 {{in expansion of macro 'recurseThrough' here}} + */ #endif } diff --git a/test/Macros/macro_expand_peers.swift b/test/Macros/macro_expand_peers.swift index dfd8a3cc0897a..6e90bf8061f67 100644 --- a/test/Macros/macro_expand_peers.swift +++ b/test/Macros/macro_expand_peers.swift @@ -317,9 +317,15 @@ struct ABIAttrWithAttachedMacro { // expected-error@+1 {{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}} @abi(@addCompletionHandler func fn1() async) @addCompletionHandler func fn1() async {} - // From diagnostics in the expansion: - // expected-note@-2 3{{in expansion of macro 'addCompletionHandler' on instance method 'fn1()' here}} - // expected-note@-4 {{'fn1()' previously declared here}} + /* + expected-expansion@-2:44{{ + expected-error@2:8{{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}} + expected-error@2:35{{invalid redeclaration of 'fn1()'}} + expected-error@4:23{{argument passed to call that takes no arguments}} + }} + expected-note@-7 3{{in expansion of macro 'addCompletionHandler' on instance method 'fn1()' here}} + expected-note@-9 {{'fn1()' previously declared here}} + */ // expected-error@+1 {{macro 'addCompletionHandler()' cannot be expanded in '@abi' attribute}} @abi(@addCompletionHandler func fn2() async) @@ -327,8 +333,13 @@ struct ABIAttrWithAttachedMacro { @abi(func fn3() async) @addCompletionHandler func fn3() async {} - // From diagnostics in the expansion: - // expected-note@-2 2{{in expansion of macro 'addCompletionHandler' on instance method 'fn3()' here}} - // expected-note@-4 {{'fn3()' previously declared here}} + /* + expected-expansion@-2:44{{ + expected-error@1:11{{invalid redeclaration of 'fn3()'}} + expected-error@3:23{{argument passed to call that takes no arguments}} + }} + expected-note@-6 2{{in expansion of macro 'addCompletionHandler' on instance method 'fn3()' here}} + expected-note@-8 {{'fn3()' previously declared here}} + */ } #endif diff --git a/test/Macros/macro_expand_synthesized_members.swift b/test/Macros/macro_expand_synthesized_members.swift index 5001f1ab9b689..08443d83bad87 100644 --- a/test/Macros/macro_expand_synthesized_members.swift +++ b/test/Macros/macro_expand_synthesized_members.swift @@ -105,12 +105,17 @@ print(ElementType.paper.unknown()) #if TEST_DIAGNOSTICS @addMembersQuotedInit struct S2 { -// expected-note@-2 {{in expansion of macro 'addMembersQuotedInit' on struct 'S2' here}} func useSynthesized() { S.method() print(type(of: getStorage())) } } +/* +expected-expansion@-2:1{{ + expected-error@14:1{{declaration name 'init()' is not covered by macro 'addMembersQuotedInit'}} +}} +expected-note@-11 {{in expansion of macro 'addMembersQuotedInit' on struct 'S2' here}} +*/ #endif @attached( diff --git a/test/Macros/top_level_freestanding.swift b/test/Macros/top_level_freestanding.swift index 1c5cd0d17bbce..4be717f1c6a08 100644 --- a/test/Macros/top_level_freestanding.swift +++ b/test/Macros/top_level_freestanding.swift @@ -12,10 +12,6 @@ // RUN: %target-typecheck-verify-swift -swift-version 5 -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -DIMPORT_MACRO_LIBRARY -swift-version 5 %S/Inputs/top_level_freestanding_other.swift -I %t -// Check diagnostic buffer names -// RUN: not %target-swift-frontend -typecheck -swift-version 5 -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5 %s %S/Inputs/top_level_freestanding_other.swift -diagnostic-style llvm 2> %t.diags -// RUN: %FileCheck -check-prefix DIAG_BUFFERS %s < %t.diags - // Execution testing // RUN: %target-build-swift -g -swift-version 5 -parse-as-library -load-plugin-library %t/%target-library-name(MacroDefinition) %s %S/Inputs/top_level_freestanding_other.swift -o %t/main -module-name MacroUser -swift-version 5 // RUN: %target-codesign %t/main @@ -60,7 +56,7 @@ func lookupGlobalFreestandingExpansion() { #anonymousTypes(public: true) { "hello" } -// CHECK-SIL: sil @$s9MacroUser03$s9A115User0033top_level_freestandingswift_DbGHjfMX60_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf_4namefMu_C5helloSSyF +// CHECK-SIL: sil @$s9MacroUser03$s9A115User0033top_level_freestandingswift_DbGHjfMX56_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf_4namefMu_C5helloSSyF @main struct Main { @@ -94,8 +90,6 @@ func testArbitraryAtGlobal() { } #endif -// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser0039top_level_freestanding_otherswift_jrGEmfMX12_17_33_7FDB3F9D78D0279543373AD342C3C331Ll9stringifyfMf1{{.*}}: warning: 'deprecated()' is deprecated -// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser0039top_level_freestanding_otherswift_jrGEmfMX16_17_33_7FDB3F9D78D0279543373AD342C3C331Ll9stringifyfMf2{{.*}}: warning: 'deprecated()' is deprecated #varValue @@ -107,15 +101,31 @@ func testGlobalVariable() { // expected-note @+1 6 {{in expansion of macro 'anonymousTypes' here}} #anonymousTypes(causeErrors: true) { "foo" } -// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser0033top_level_freestandingswift_DbGHjfMX108_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf0_{{.*}}: warning: use of protocol 'Equatable' as a type must be written 'any Equatable' -// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser00142___swiftmacro_9MacroUser0033top_level_freestandingswift_DbGHjfMX108_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf0_swift_DAIABdjIbfMX23_2_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll27introduceTypeCheckingErrorsfMf_{{.*}}: warning: use of protocol 'Hashable' as a type must be written 'any Hashable' - +/* +expected-expansion@-2:1 {{ + expected-warning@23:8{{same-type requirement makes generic parameter 'T' non-generic; this is an error in the Swift 6 language mode}} + expected-note@23:135{{'T' previously declared here}} + expected-warning@23:149{{use of protocol 'Equatable' as a type must be written 'any Equatable'; this will be an error in a future Swift language mode}} + expected-note@24:3 3{{in expansion of macro 'introduceTypeCheckingErrors' here}} + expected-expansion@24:3 {{ + expected-warning@2:10{{same-type requirement makes generic parameter 'T' non-generic; this is an error in the Swift 6 language mode}} + expected-warning@2:259{{generic parameter 'T' shadows generic parameter from outer scope with the same name; this is an error in the Swift 6 language mode}} + expected-warning@2:273{{use of protocol 'Hashable' as a type must be written 'any Hashable'; this will be an error in a future Swift language mode}} + }} +}} +*/ // expected-note @+1 2 {{in expansion of macro 'anonymousTypes' here}} #anonymousTypes { () -> String in // expected-warning @+1 {{use of protocol 'Equatable' as a type must be written 'any Equatable'}} _ = 0 as Equatable return "foo" } +/* +expected-expansion@-6:1{{ + expected-warning@5:16{{use of protocol 'Equatable' as a type must be written 'any Equatable'; this will be an error in a future Swift language mode}} + expected-warning@20:16{{use of protocol 'Equatable' as a type must be written 'any Equatable'; this will be an error in a future Swift language mode}} +}} +*/ #endif @@ -165,3 +175,4 @@ func testFunctionCallWithInoutParam() { #functionCallWithTwoInoutParams(&a, &b) #functionCallWithInoutParamPlusOthers(string: "", double: 1.0, &a) } +