@@ -306,13 +306,6 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
306
306
// Delay issuing the diagnostic until we parse the attribute.
307
307
DiscardAttribute = true ;
308
308
}
309
-
310
- if ((DK == DAK_Prefix || DK == DAK_Postfix) && !DiscardAttribute &&
311
- Attributes.getUnaryOperatorKind () != UnaryOperatorKind::None) {
312
- diagnose (Loc, diag::cannot_combine_attribute,
313
- DK == DAK_Prefix ? " postfix" : " prefix" );
314
- DiscardAttribute = true ;
315
- }
316
309
317
310
// If this is a SIL-only attribute, reject it.
318
311
if ((DeclAttribute::getOptions (DK) & DeclAttribute::SILOnly) != 0 &&
@@ -1597,6 +1590,51 @@ static bool isStartOfOperatorDecl(const Token &Tok, const Token &Tok2) {
1597
1590
Tok2.isContextualKeyword (" infix" ));
1598
1591
}
1599
1592
1593
+ // / \brief Diagnose issues with fixity attributes, if any.
1594
+ static void diagnoseOperatorFixityAttributes (Parser &P,
1595
+ DeclAttributes &Attrs,
1596
+ const Decl *D) {
1597
+ auto isFixityAttr = [](DeclAttribute *attr){
1598
+ DeclAttrKind kind = attr->getKind ();
1599
+ return attr->isValid () && (kind == DAK_Prefix ||
1600
+ kind == DAK_Infix ||
1601
+ kind == DAK_Postfix);
1602
+ };
1603
+
1604
+ SmallVector<DeclAttribute *, 3 > fixityAttrs;
1605
+ std::copy_if (Attrs.begin (), Attrs.end (),
1606
+ std::back_inserter (fixityAttrs), isFixityAttr);
1607
+ std::reverse (fixityAttrs.begin (), fixityAttrs.end ());
1608
+
1609
+ for (auto it = fixityAttrs.begin (); it != fixityAttrs.end (); ++it) {
1610
+ if (it != fixityAttrs.begin ()) {
1611
+ auto *attr = *it;
1612
+ P.diagnose (attr->getLocation (), diag::mutually_exclusive_attrs,
1613
+ attr->getAttrName (), fixityAttrs.front ()->getAttrName (),
1614
+ attr->isDeclModifier ())
1615
+ .fixItRemove (attr->getRange ());
1616
+ attr->setInvalid ();
1617
+ }
1618
+ }
1619
+
1620
+ // Operator declarations must specify a fixity.
1621
+ if (auto *OD = dyn_cast<OperatorDecl>(D)) {
1622
+ if (fixityAttrs.empty ()) {
1623
+ P.diagnose (OD->getOperatorLoc (), diag::operator_decl_no_fixity);
1624
+ }
1625
+ }
1626
+ // Infix operator is only allowed on operator declarations, not on func.
1627
+ else if (isa<FuncDecl>(D)) {
1628
+ if (auto *attr = Attrs.getAttribute <InfixAttr>()) {
1629
+ P.diagnose (attr->getLocation (), diag::invalid_infix_on_func)
1630
+ .fixItRemove (attr->getLocation ());
1631
+ attr->setInvalid ();
1632
+ }
1633
+ } else {
1634
+ llvm_unreachable (" unexpected decl kind?" );
1635
+ }
1636
+ }
1637
+
1600
1638
static bool isKeywordPossibleDeclStart (const Token &Tok) {
1601
1639
switch (Tok.getKind ()) {
1602
1640
case tok::at_sign:
@@ -4479,6 +4517,8 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
4479
4517
GenericParams, BodyParams, Type (), FuncRetTy,
4480
4518
CurDeclContext);
4481
4519
4520
+ diagnoseOperatorFixityAttributes (*this , Attributes, FD);
4521
+
4482
4522
// Add the attributes here so if we need them while parsing the body
4483
4523
// they are available.
4484
4524
FD->getAttrs () = Attributes;
@@ -5512,23 +5552,20 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
5512
5552
(void ) consumeIf (tok::r_brace);
5513
5553
}
5514
5554
5515
-
5516
5555
OperatorDecl *res;
5517
5556
if (Attributes.hasAttribute <PrefixAttr>())
5518
5557
res = new (Context) PrefixOperatorDecl (CurDeclContext, OperatorLoc,
5519
5558
Name, NameLoc);
5520
5559
else if (Attributes.hasAttribute <PostfixAttr>())
5521
5560
res = new (Context) PostfixOperatorDecl (CurDeclContext, OperatorLoc,
5522
5561
Name, NameLoc);
5523
- else {
5524
- if (!Attributes.hasAttribute <InfixAttr>())
5525
- diagnose (OperatorLoc, diag::operator_decl_no_fixity);
5526
-
5562
+ else
5527
5563
res = new (Context) InfixOperatorDecl (CurDeclContext, OperatorLoc,
5528
5564
Name, NameLoc, colonLoc,
5529
5565
precedenceGroupName,
5530
5566
precedenceGroupNameLoc);
5531
- }
5567
+
5568
+ diagnoseOperatorFixityAttributes (*this , Attributes, res);
5532
5569
5533
5570
res->getAttrs () = Attributes;
5534
5571
return makeParserResult (res);
0 commit comments