@@ -1372,6 +1372,125 @@ void Parser::parseObjCSelector(SmallVector<Identifier, 4> &Names,
13721372 }
13731373}
13741374
1375+ bool Parser::peekAvailabilityMacroName () {
1376+ parseAllAvailabilityMacroArguments ();
1377+ AvailabilityMacroMap Map = AvailabilityMacros;
1378+
1379+ StringRef MacroName = Tok.getText ();
1380+ return Map.find (MacroName) != Map.end ();
1381+ }
1382+
1383+ ParserStatus
1384+ Parser::parseAvailabilityMacro (SmallVectorImpl<AvailabilitySpec *> &Specs) {
1385+ // Get the macros from the compiler arguments.
1386+ parseAllAvailabilityMacroArguments ();
1387+ AvailabilityMacroMap Map = AvailabilityMacros;
1388+
1389+ StringRef MacroName = Tok.getText ();
1390+ auto NameMatch = Map.find (MacroName);
1391+ if (NameMatch == Map.end ())
1392+ return makeParserSuccess (); // No match, it could be a standard platform.
1393+
1394+ consumeToken ();
1395+
1396+ llvm::VersionTuple Version;
1397+ SourceRange VersionRange;
1398+ if (Tok.isAny (tok::integer_literal, tok::floating_literal)) {
1399+ if (parseVersionTuple (Version, VersionRange,
1400+ diag::avail_query_expected_version_number))
1401+ return makeParserError ();
1402+ }
1403+
1404+ auto VersionMatch = NameMatch->getSecond ().find (Version);
1405+ if (VersionMatch == NameMatch->getSecond ().end ()) {
1406+ diagnose (PreviousLoc, diag::attr_availability_unknown_version,
1407+ Version.getAsString (), MacroName);
1408+ return makeParserError (); // Failed to match the version, that's an error.
1409+ }
1410+
1411+ // Make a copy of the specs to add the macro source location
1412+ // for the diagnostic about the use of macros in inlinable code.
1413+ SourceLoc MacroLoc = Tok.getLoc ();
1414+ for (auto *Spec : VersionMatch->getSecond ())
1415+ if (auto *PlatformVersionSpec =
1416+ dyn_cast<PlatformVersionConstraintAvailabilitySpec>(Spec)) {
1417+ auto SpecCopy =
1418+ new (Context) PlatformVersionConstraintAvailabilitySpec (
1419+ *PlatformVersionSpec);
1420+ SpecCopy->setMacroLoc (MacroLoc);
1421+ Specs.push_back (SpecCopy);
1422+ }
1423+
1424+ return makeParserSuccess ();
1425+ }
1426+
1427+ void Parser::parseAllAvailabilityMacroArguments () {
1428+
1429+ if (AvailabilityMacrosComputed) return ;
1430+
1431+ AvailabilityMacroMap Map;
1432+
1433+ SourceManager &SM = Context.SourceMgr ;
1434+ const LangOptions &LangOpts = Context.LangOpts ;
1435+
1436+ for (StringRef macro: LangOpts.AvailabilityMacros ) {
1437+
1438+ // Create temporary parser.
1439+ int bufferID = SM.addMemBufferCopy (macro,
1440+ " -define-availability argument" );
1441+ swift::ParserUnit PU (SM,
1442+ SourceFileKind::Main, bufferID,
1443+ LangOpts,
1444+ TypeCheckerOptions (), " unknown" );
1445+
1446+ ForwardingDiagnosticConsumer PDC (Context.Diags );
1447+ PU.getDiagnosticEngine ().addConsumer (PDC);
1448+
1449+ // Parse the argument.
1450+ AvailabilityMacroDefinition ParsedMacro;
1451+ ParserStatus Status =
1452+ PU.getParser ().parseAvailabilityMacroDefinition (ParsedMacro);
1453+ if (Status.isError ())
1454+ continue ;
1455+
1456+ // Copy the Specs to the requesting ASTContext from the temporary context
1457+ // that parsed the argument.
1458+ auto SpecsCopy = SmallVector<AvailabilitySpec*, 4 >();
1459+ for (auto *Spec : ParsedMacro.Specs )
1460+ if (auto *PlatformVersionSpec =
1461+ dyn_cast<PlatformVersionConstraintAvailabilitySpec>(Spec)) {
1462+ auto SpecCopy =
1463+ new (Context) PlatformVersionConstraintAvailabilitySpec (
1464+ *PlatformVersionSpec);
1465+ SpecsCopy.push_back (SpecCopy);
1466+ }
1467+
1468+ ParsedMacro.Specs = SpecsCopy;
1469+
1470+ // Find the macro info by name.
1471+ AvailabilityMacroVersionMap MacroDefinition;
1472+ auto NameMatch = Map.find (ParsedMacro.Name );
1473+ if (NameMatch != Map.end ()) {
1474+ MacroDefinition = NameMatch->getSecond ();
1475+ }
1476+
1477+ // Set the macro info by version.
1478+ auto PreviousEntry =
1479+ MacroDefinition.insert ({ParsedMacro.Version , ParsedMacro.Specs });
1480+ if (!PreviousEntry.second ) {
1481+ diagnose (PU.getParser ().PreviousLoc , diag::attr_availability_duplicate,
1482+ ParsedMacro.Name , ParsedMacro.Version .getAsString ());
1483+ }
1484+
1485+ // Save back the macro spec.
1486+ Map.erase (ParsedMacro.Name );
1487+ Map.insert ({ParsedMacro.Name , MacroDefinition});
1488+ }
1489+
1490+ AvailabilityMacros = Map;
1491+ AvailabilityMacrosComputed = true ;
1492+ }
1493+
13751494bool Parser::parseNewDeclAttribute (DeclAttributes &Attributes, SourceLoc AtLoc,
13761495 DeclAttrKind DK) {
13771496 // Ok, it is a valid attribute, eat it, and then process it.
@@ -1975,7 +2094,8 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
19752094 StringRef Platform = Tok.getText ();
19762095
19772096 if (Platform != " *" &&
1978- peekToken ().isAny (tok::integer_literal, tok::floating_literal)) {
2097+ (peekToken ().isAny (tok::integer_literal, tok::floating_literal) ||
2098+ peekAvailabilityMacroName ())) {
19792099 // We have the short form of available: @available(iOS 8.0.1, *)
19802100 SmallVector<AvailabilitySpec *, 5 > Specs;
19812101 ParserStatus Status = parseAvailabilitySpecList (Specs);
0 commit comments