1) Redesign DeclAttributes to be based around an array indexed by attribute, instead

of having a ton of ad-hoc bools in it.  This allows us to consolidate a ton of 
   boilerplate, eliminating 250 lines of code:

 17 files changed, 435 insertions(+), 662 deletions(-)

2) This eliminates the special case for weak and unowned attributes, which previously
   didn't show up in Attr.def.

3) While we're at it, keep track of proper source locations for each attribute, and
   use these to emit diagnostics pointing at the attribute in question instead of at
   a funcdecl or the @ sign.

4) Fix axle attributes, which had vertex and fragment swapped.



Swift SVN r9263
This commit is contained in:
Chris Lattner
2013-10-13 01:25:50 +00:00
parent a718c8f57a
commit 09705dc7cd
13 changed files with 351 additions and 578 deletions

View File

@@ -41,6 +41,8 @@ ATTR(iboutlet)
ATTR(ibaction) ATTR(ibaction)
ATTR(local_storage) ATTR(local_storage)
ATTR(transparent) ATTR(transparent)
ATTR(weak)
ATTR(unowned)
// SIL-specific attributes // SIL-specific attributes
ATTR(sil_self) ATTR(sil_self)

View File

@@ -99,6 +99,8 @@ public:
/// defining a resilient structure need not actually use resilience /// defining a resilient structure need not actually use resilience
/// boundaries. /// boundaries.
enum class Resilience : unsigned char { enum class Resilience : unsigned char {
Default,
/// Inherently fragile language structures are not only resilient, /// Inherently fragile language structures are not only resilient,
/// but they have never been exposed as resilient. This permits /// but they have never been exposed as resilient. This permits
/// certain kinds of optimizations that are not otherwise possible /// certain kinds of optimizations that are not otherwise possible
@@ -114,115 +116,119 @@ enum class Resilience : unsigned char {
Resilient Resilient
}; };
class ResilienceData {
unsigned Valid : 1;
unsigned Kind : 2;
public:
ResilienceData() : Valid(false) {}
ResilienceData(Resilience resil) : Valid(true), Kind(unsigned(resil)) {}
bool isValid() const { return Valid; }
Resilience getResilience() const {
assert(Valid);
return Resilience(Kind);
}
};
enum class AbstractCC : unsigned char; enum class AbstractCC : unsigned char;
// Define enumerators for each attribute, e.g. AK_weak.
#define MAKE_ENUMERATOR(id) id,
enum AttrKind {
#define ATTR(X) AK_##X,
#include "swift/AST/Attr.def"
AK_Count
};
/// DeclAttributes - These are attributes that may be applied to declarations. /// DeclAttributes - These are attributes that may be applied to declarations.
class DeclAttributes { class DeclAttributes {
// Get a SourceLoc for every possible attribute that can be parsed in source.
// the presence of the attribute is indicated by its location being set.
SourceLoc AttrLocs[AK_Count];
bool HasAttr[AK_Count] = { false };
public: public:
/// AtLoc - This is the location of the first '@' in the attribute specifier. /// AtLoc - This is the location of the first '@' in the attribute specifier.
/// If this is an empty attribute specifier, then this will be an invalid loc. /// If this is an empty attribute specifier, then this will be an invalid loc.
SourceLoc AtLoc; SourceLoc AtLoc;
ResilienceData Resilience;
StringRef AsmName; StringRef AsmName;
bool InOut = false;
bool AutoClosure = false;
bool Thin = false;
bool NoReturn = false;
bool Assignment = false;
bool Conversion = false;
bool Transparent = false;
bool ObjC = false;
bool ObjCBlock = false;
bool ExplicitPrefix = false;
bool ExplicitPostfix = false;
bool ExplicitInfix = false;
bool IBOutlet = false;
bool IBAction = false;
bool ClassProtocol = false;
bool Weak = false;
bool Unowned = false;
bool LocalStorage = false;
bool Exported = false;
Optional<AbstractCC> cc = Nothing; Optional<AbstractCC> cc = Nothing;
bool SILSelf = false;
KernelOrShaderKind KernelOrShader = KernelOrShaderKind::Default;
DeclAttributes() {} DeclAttributes() {}
bool isValid() const { return AtLoc.isValid(); } bool isValid() const { return AtLoc.isValid(); }
ResilienceData getResilienceData() const { return Resilience; } void clearAttribute(AttrKind A) {
bool isInOut() const { return InOut; } AttrLocs[A] = SourceLoc();
bool isAutoClosure() const { return AutoClosure; } HasAttr[A] = false;
bool isThin() const { return Thin; }
bool isNoReturn() const { return NoReturn; }
bool isAssignment() const { return Assignment; }
bool isConversion() const { return Conversion; }
bool isTransparent() const { return Transparent; }
bool isPrefix() const { return ExplicitPrefix; }
bool isPostfix() const { return ExplicitPostfix; }
bool isInfix() const { return ExplicitInfix; }
bool isObjC() const { return ObjC; }
bool isObjCBlock() const { return ObjCBlock; }
bool isIBOutlet() const { return IBOutlet; }
bool isIBAction() const { return IBAction; }
bool isClassProtocol() const { return ClassProtocol; }
bool isLocalStorage() const { return LocalStorage; }
bool isWeak() const { return Weak; }
bool isUnowned() const { return Unowned; }
bool hasOwnership() const { return Weak || Unowned; }
Ownership getOwnership() const {
if (Weak) return Ownership::Weak;
if (Unowned) return Ownership::Unowned;
return Ownership::Strong;
} }
bool isExported() const { return Exported; }
bool has(AttrKind A) const {
return HasAttr[A];
}
SourceLoc getLoc(AttrKind A) const {
return AttrLocs[A];
}
void setAttr(AttrKind A, SourceLoc L) {
AttrLocs[A] = L;
HasAttr[A] = true;
}
// This attribute list is empty if no attributes are specified. Note that
// the presence of the leading @ is not enough to tell, because we want
// clients to be able to remove attributes they process until they get to
// an empty list.
bool empty() const {
for (bool elt : HasAttr)
if (elt) return false;
return true;
}
bool isInOut() const { return has(AK_inout); }
bool isAutoClosure() const { return has(AK_auto_closure); }
bool isThin() const { return has(AK_thin); }
bool isNoReturn() const { return has(AK_noreturn); }
bool isAssignment() const { return has(AK_assignment); }
bool isConversion() const { return has(AK_conversion); }
bool isTransparent() const {return has(AK_transparent);}
bool isPrefix() const { return has(AK_prefix); }
bool isPostfix() const { return has(AK_postfix); }
bool isInfix() const { return has(AK_infix); }
bool isObjC() const { return has(AK_objc); }
bool isObjCBlock() const { return has(AK_objc_block); }
bool isIBOutlet() const { return has(AK_iboutlet); }
bool isIBAction() const { return has(AK_ibaction); }
bool isClassProtocol() const { return has(AK_class_protocol); }
bool isLocalStorage() const { return has(AK_local_storage); }
bool isWeak() const { return has(AK_weak); }
bool isUnowned() const { return has(AK_unowned); }
bool isExported() const { return has(AK_exported); }
bool isSILSelf() const { return has(AK_sil_self); }
bool isKernel() const { return has(AK_kernel); }
bool isVertex() const { return has(AK_vertex); }
bool isFragment() const { return has(AK_fragment); }
bool hasCC() const { return cc.hasValue(); } bool hasCC() const { return cc.hasValue(); }
AbstractCC getAbstractCC() const { return *cc; } AbstractCC getAbstractCC() const { return *cc; }
bool isSILSelf() const { return SILSelf; }
Resilience getResilienceKind() const {
if (has(AK_resilient))
return Resilience::Resilient;
if (has(AK_fragile))
return Resilience::Fragile;
if (has(AK_born_fragile))
return Resilience::InherentlyFragile;
return Resilience::Default;
}
bool hasOwnership() const { return isWeak() || isUnowned(); }
Ownership getOwnership() const {
if (isWeak()) return Ownership::Weak;
if (isUnowned()) return Ownership::Unowned;
return Ownership::Strong;
}
KernelOrShaderKind getKernelOrShaderKind() const { KernelOrShaderKind getKernelOrShaderKind() const {
return KernelOrShader; if (isKernel()) return KernelOrShaderKind::Kernel;
} if (isVertex()) return KernelOrShaderKind::Fragment;
bool isKernel() const { if (isFragment()) return KernelOrShaderKind::Vertex;
return KernelOrShader == KernelOrShaderKind::Kernel; return KernelOrShaderKind::Default;
}
bool isVertex() const {
return KernelOrShader == KernelOrShaderKind::Vertex;
}
bool isFragment() const {
return KernelOrShader == KernelOrShaderKind::Fragment;
}
bool empty() const {
return !isInfix() && !getResilienceData().isValid() && !isInOut() &&
!isAutoClosure() && !isThin() && !isNoReturn() && !isAssignment() &&
!isConversion() && !isTransparent() && !isPostfix() && !isPrefix() &&
!isObjC() && !isObjCBlock() && !isIBOutlet() && !isIBAction() &&
!isClassProtocol() && !hasCC() && !hasOwnership() &&
!isLocalStorage() && !isExported() && AsmName.empty() &&
!isSILSelf() &&
getKernelOrShaderKind() == KernelOrShaderKind::Default;
} }
void clearOwnership() { void clearOwnership() {
Weak = Unowned = false; clearAttribute(AK_weak);
clearAttribute(AK_unowned);
} }
}; };

View File

@@ -781,8 +781,8 @@ ERROR(cannot_combine_attribute,attribute_parsing,none,
ERROR(expected_in_attribute_list,attribute_parsing,none, ERROR(expected_in_attribute_list,attribute_parsing,none,
"expected ']' or ',' in attribute list", ()) "expected ']' or ',' in attribute list", ())
ERROR(invalid_attribute_for_lang,attribute_parsing,none, ERROR(invalid_attribute_for_lang,attribute_parsing,none,
"attribute '%0' is only valid in language mode '%select{axle}1'", "attribute is only valid in language mode '%select{axle}0'",
(StringRef, unsigned)) (unsigned))
ERROR(expected_decl_attribute_not_type,attribute_parsing,none, ERROR(expected_decl_attribute_not_type,attribute_parsing,none,
"expected declaration attribute, not a type attribute", ()) "expected declaration attribute, not a type attribute", ())
@@ -1082,7 +1082,7 @@ ERROR(class_protocol_not_protocol,sema_tcd,none,
"'class_protocol' attribute can only be applied to protocols", ()) "'class_protocol' attribute can only be applied to protocols", ())
ERROR(invalid_decl_attribute,sema_tcd,none, ERROR(invalid_decl_attribute,sema_tcd,none,
"attribute '%0' cannot be applied to declaration", (StringRef)) "attribute cannot be applied to declaration", ())
// Extensions // Extensions
ERROR(non_nominal_extension,sema_tcd,none, ERROR(non_nominal_extension,sema_tcd,none,

View File

@@ -178,20 +178,11 @@ void PrintAST::printAttributes(const DeclAttributes &Attrs) {
AP.next() << "transparent"; AP.next() << "transparent";
if (Attrs.isInfix()) if (Attrs.isInfix())
AP.next() << "infix"; AP.next() << "infix";
if (Attrs.getResilienceData().isValid()) { switch (Attrs.getResilienceKind()) {
switch (Attrs.getResilienceData().getResilience()) { case Resilience::Default: break;
case Resilience::Fragile: case Resilience::Fragile: AP.next() << "fragile"; break;
AP.next() << "fragile"; case Resilience::InherentlyFragile: AP.next() << "born_fragile"; break;
break; case Resilience::Resilient: AP.next() << "resilient"; break;
case Resilience::InherentlyFragile:
AP.next() << "born_fragile";
break;
case Resilience::Resilient:
AP.next() << "resilient";
break;
}
} }
if (Attrs.isInOut()) if (Attrs.isInOut())
AP.next() << "inout"; AP.next() << "inout";

View File

@@ -90,12 +90,11 @@ void AttributedTypeRepr::printAttrs(llvm::raw_ostream &OS) const {
const DeclAttributes &Attrs = getAttrs(); const DeclAttributes &Attrs = getAttrs();
llvm::SmallString<64> AttrStr; llvm::SmallString<64> AttrStr;
llvm::raw_svector_ostream AttrOS(AttrStr); llvm::raw_svector_ostream AttrOS(AttrStr);
if (Attrs.Resilience.isValid()) { switch (Attrs.getResilienceKind()) {
switch (Attrs.Resilience.getResilience()) { case Resilience::Default: break;
case Resilience::InherentlyFragile: AttrOS << "born_fragile,"; break; case Resilience::InherentlyFragile: AttrOS << "born_fragile,"; break;
case Resilience::Fragile: AttrOS << "fragile,"; break; case Resilience::Fragile: AttrOS << "fragile,"; break;
case Resilience::Resilient: AttrOS << "resilient,"; break; case Resilience::Resilient: AttrOS << "resilient,"; break;
}
} }
if (!Attrs.AsmName.empty()) if (!Attrs.AsmName.empty())
AttrOS << "asmname=\"" << Attrs.AsmName << "\","; AttrOS << "asmname=\"" << Attrs.AsmName << "\",";

View File

@@ -290,7 +290,8 @@ namespace {
} }
Decl * Decl *
VisitUnresolvedUsingTypenameDecl(const clang::UnresolvedUsingTypenameDecl *decl) { VisitUnresolvedUsingTypenameDecl(const
clang::UnresolvedUsingTypenameDecl *decl) {
// Note: only occurs in templates. // Note: only occurs in templates.
return nullptr; return nullptr;
} }
@@ -831,7 +832,7 @@ namespace {
// Handle attributes. // Handle attributes.
if (decl->hasAttr<clang::IBOutletAttr>()) if (decl->hasAttr<clang::IBOutletAttr>())
result->getMutableAttrs().IBOutlet = true; result->getMutableAttrs().setAttr(AK_iboutlet, SourceLoc());
// FIXME: Handle IBOutletCollection. // FIXME: Handle IBOutletCollection.
return result; return result;
@@ -917,7 +918,8 @@ namespace {
return VisitObjCMethodDecl(decl, dc); return VisitObjCMethodDecl(decl, dc);
} }
Decl *VisitObjCMethodDecl(const clang::ObjCMethodDecl *decl, DeclContext *dc) { Decl *VisitObjCMethodDecl(const clang::ObjCMethodDecl *decl,
DeclContext *dc) {
auto loc = Impl.importSourceLoc(decl->getLocStart()); auto loc = Impl.importSourceLoc(decl->getLocStart());
// The name of the method is the first part of the selector. // The name of the method is the first part of the selector.
@@ -989,7 +991,7 @@ namespace {
setVarDeclContexts(bodyPatterns, result); setVarDeclContexts(bodyPatterns, result);
// Mark this as an Objective-C method. // Mark this as an Objective-C method.
result->getMutableAttrs().ObjC = true; result->getMutableAttrs().setAttr(AK_objc, SourceLoc());
result->setIsObjC(true); result->setIsObjC(true);
// Mark class methods as static. // Mark class methods as static.
@@ -1034,7 +1036,7 @@ namespace {
// Handle attributes. // Handle attributes.
if (decl->hasAttr<clang::IBActionAttr>()) if (decl->hasAttr<clang::IBActionAttr>())
result->getMutableAttrs().IBAction = true; result->getMutableAttrs().setAttr(AK_ibaction, SourceLoc());
// Check whether there's some special method to import. // Check whether there's some special method to import.
result->setClangNode(decl); result->setClangNode(decl);
@@ -1975,8 +1977,8 @@ namespace {
result->setCheckedInheritanceClause(); result->setCheckedInheritanceClause();
// Note that this is an Objective-C and class protocol. // Note that this is an Objective-C and class protocol.
result->getMutableAttrs().ObjC = true; result->getMutableAttrs().setAttr(AK_objc, SourceLoc());
result->getMutableAttrs().ClassProtocol = true; result->getMutableAttrs().setAttr(AK_class_protocol, SourceLoc());
result->setIsObjC(true); result->setIsObjC(true);
// Add the implicit 'Self' associated type. // Add the implicit 'Self' associated type.
@@ -2049,7 +2051,7 @@ namespace {
result->setCheckedInheritanceClause(); result->setCheckedInheritanceClause();
// Note that this is an Objective-C class. // Note that this is an Objective-C class.
result->getMutableAttrs().ObjC = true; result->getMutableAttrs().setAttr(AK_objc, SourceLoc());
result->setIsObjC(true); result->setIsObjC(true);
// Import each of the members. // Import each of the members.
@@ -2160,12 +2162,11 @@ namespace {
// Handle attributes. // Handle attributes.
if (decl->hasAttr<clang::IBOutletAttr>()) if (decl->hasAttr<clang::IBOutletAttr>())
result->getMutableAttrs().IBOutlet = true; result->getMutableAttrs().setAttr(AK_iboutlet, SourceLoc());
// FIXME: Handle IBOutletCollection. // FIXME: Handle IBOutletCollection.
if (overridden) { if (overridden)
result->setOverriddenDecl(overridden); result->setOverriddenDecl(overridden);
}
return result; return result;
} }
@@ -2233,7 +2234,8 @@ namespace {
} }
/// \brief Classify the given Clang enumeration to describe how it /// \brief Classify the given Clang enumeration to describe how it
EnumKind ClangImporter::Implementation::classifyEnum(const clang::EnumDecl *decl) { EnumKind ClangImporter::Implementation::
classifyEnum(const clang::EnumDecl *decl) {
Identifier name; Identifier name;
if (decl->getDeclName()) if (decl->getDeclName())
name = importName(decl->getDeclName()); name = importName(decl->getDeclName());
@@ -2275,8 +2277,8 @@ Decl *ClangImporter::Implementation::importDecl(const clang::NamedDecl *decl) {
} }
Decl * Decl *
ClangImporter::Implementation::importMirroredDecl(const clang::ObjCMethodDecl *decl, ClangImporter::Implementation::
DeclContext *dc) { importMirroredDecl(const clang::ObjCMethodDecl *decl, DeclContext *dc) {
if (!decl) if (!decl)
return nullptr; return nullptr;

View File

@@ -1358,7 +1358,7 @@ ClassDecl *IRGenModule::getSwiftRootClass() {
/*generics*/ nullptr, /*generics*/ nullptr,
Context.TheBuiltinModule); Context.TheBuiltinModule);
SwiftRootClass->computeType(); SwiftRootClass->computeType();
SwiftRootClass->getMutableAttrs().ObjC = true; SwiftRootClass->getMutableAttrs().setAttr(AK_objc, SourceLoc());
SwiftRootClass->setIsObjC(true); SwiftRootClass->setIsObjC(true);
return SwiftRootClass; return SwiftRootClass;
} }

View File

@@ -98,29 +98,11 @@ bool Parser::parseTopLevel() {
return FoundTopLevelCodeToExecute; return FoundTopLevelCodeToExecute;
} }
namespace { static AttrKind getAttrName(StringRef text) {
#define MAKE_ENUMERATOR(id) id, return llvm::StringSwitch<AttrKind>(text)
enum class AttrName { #define ATTR(X) .Case(#X, AK_##X)
none,
#define ATTR(X) X,
#include "swift/AST/Attr.def" #include "swift/AST/Attr.def"
}; .Default(AK_Count);
}
static AttrName getAttrName(StringRef text) {
return llvm::StringSwitch<AttrName>(text)
#define ATTR(X) .Case(#X, AttrName::X)
#include "swift/AST/Attr.def"
.Default(AttrName::none);
}
static Resilience getResilience(AttrName attr) {
switch (attr) {
case AttrName::resilient: return Resilience::Resilient;
case AttrName::fragile: return Resilience::Fragile;
case AttrName::born_fragile: return Resilience::InherentlyFragile;
default: llvm_unreachable("bad resilience");
}
} }
/// \verbatim /// \verbatim
@@ -137,35 +119,18 @@ static Resilience getResilience(AttrName attr) {
/// \endverbatim /// \endverbatim
bool Parser::parseAttribute(DeclAttributes &Attributes, unsigned KindMask, bool Parser::parseAttribute(DeclAttributes &Attributes, unsigned KindMask,
bool OldStyle) { bool OldStyle) {
if (Tok.is(tok::kw_weak)) { // If this not an identifier, the attribute is malformed.
auto Loc = consumeToken(tok::kw_weak); if (Tok.isNot(tok::identifier) &&
Tok.isNot(tok::kw_weak) &&
if (Attributes.hasOwnership()) Tok.isNot(tok::kw_unowned)) {
diagnose(Loc, diag::duplicate_attribute);
else
Attributes.Weak = true;
return false;
}
if (Tok.is(tok::kw_unowned)) {
auto Loc = consumeToken(tok::kw_unowned);
if (Attributes.hasOwnership())
diagnose(Loc, diag::duplicate_attribute);
else
Attributes.Unowned = true;
return false;
}
if (!Tok.is(tok::identifier)) {
diagnose(Tok, diag::expected_attribute_name); diagnose(Tok, diag::expected_attribute_name);
if (OldStyle) skipUntil(tok::r_square); if (OldStyle) skipUntil(tok::r_square);
return true; return true;
} }
switch (AttrName attr = getAttrName(Tok.getText())) { // Determine which attribute it is, and diagnose it if unknown.
case AttrName::none: AttrKind attr = getAttrName(Tok.getText());
if (attr == AK_Count) {
diagnose(Tok, diag::unknown_attribute, Tok.getText()); diagnose(Tok, diag::unknown_attribute, Tok.getText());
if (OldStyle) if (OldStyle)
skipUntil(tok::r_square); skipUntil(tok::r_square);
@@ -182,66 +147,55 @@ bool Parser::parseAttribute(DeclAttributes &Attributes, unsigned KindMask,
} }
} }
return true; return true;
// Infix attributes.
case AttrName::infix: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.isInfix())
diagnose(Loc, diag::duplicate_attribute);
else
Attributes.ExplicitInfix = true;
return false;
} }
// SIL's 'local_storage' type attribute. // Ok, it is a valid attribute, eat it, and then process it.
case AttrName::local_storage: { SourceLoc Loc = consumeToken();
auto Loc = consumeToken(tok::identifier);
if (Attributes.isLocalStorage()) // Diagnose duplicated attributes.
diagnose(Loc, diag::duplicate_attribute); if (Attributes.has(attr))
else if (!isInSILMode()) diagnose(Loc, diag::duplicate_attribute);
else
Attributes.setAttr(attr, Loc);
// Handle any attribute-specific processing logic.
switch (attr) {
default: break;
case AK_local_storage:
case AK_sil_self:
if (!isInSILMode()) // SIL's 'local_storage' type attribute.
diagnose(Loc, diag::only_allowed_in_sil, "local_storage"); diagnose(Loc, diag::only_allowed_in_sil, "local_storage");
else break;
Attributes.LocalStorage = true;
return false;
}
// SIL's 'sil_self' type attribute. // Ownership attributes.
case AttrName::sil_self: { case AK_weak:
auto Loc = consumeToken(tok::identifier); case AK_unowned:
if (Attributes.isSILSelf()) // Test for duplicate entries by temporarily removing this one.
Attributes.clearAttribute(attr);
if (Attributes.hasOwnership()) {
diagnose(Loc, diag::duplicate_attribute); diagnose(Loc, diag::duplicate_attribute);
else if (!isInSILMode()) break;
diagnose(Loc, diag::only_allowed_in_sil, "sil_self"); }
else Attributes.setAttr(attr, Loc);
Attributes.SILSelf = true; break;
return false;
}
// Resilience attributes. // Resilience attributes.
case AttrName::resilient: case AK_resilient:
case AttrName::fragile: case AK_fragile:
case AttrName::born_fragile: { case AK_born_fragile:
auto Loc = consumeToken(tok::identifier); // Test for duplicate entries by temporarily removing this one.
if (Attributes.Resilience.isValid()) Attributes.clearAttribute(attr);
if (Attributes.getResilienceKind() != Resilience::Default) {
diagnose(Loc, diag::duplicate_attribute); diagnose(Loc, diag::duplicate_attribute);
else { break;
Resilience resil = getResilience(attr);
// TODO: 'fragile' should allow deployment versioning.
Attributes.Resilience = ResilienceData(resil);
} }
return false; Attributes.setAttr(attr, Loc);
} break;
// 'inout' attribute. // 'inout' attribute.
// FIXME: only permit this in specific contexts. // FIXME: only permit this in specific contexts.
case AttrName::inout: { case AK_inout: {
SourceLoc TokLoc = consumeToken(tok::identifier);
if (Attributes.InOut)
diagnose(Tok, diag::duplicate_attribute);
Attributes.InOut = true;
// Permit "qualifiers" on the inout. // Permit "qualifiers" on the inout.
SourceLoc beginLoc = Tok.getLoc(); SourceLoc beginLoc = Tok.getLoc();
if (consumeIfNotAtStartOfLine(tok::l_paren)) { if (consumeIfNotAtStartOfLine(tok::l_paren)) {
@@ -255,19 +209,26 @@ bool Parser::parseAttribute(DeclAttributes &Attributes, unsigned KindMask,
// Verify that we're not combining this attribute incorrectly. Cannot be // Verify that we're not combining this attribute incorrectly. Cannot be
// both inout and auto_closure. // both inout and auto_closure.
if (Attributes.isAutoClosure()) { if (Attributes.isAutoClosure()) {
diagnose(TokLoc, diag::cannot_combine_attribute, "auto_closure"); diagnose(Loc, diag::cannot_combine_attribute, "auto_closure");
Attributes.AutoClosure = false; Attributes.clearAttribute(attr);
} }
return false; break;
} }
// FIXME: Only valid on var and tuple elements, not on func's, typealias, etc.
case AK_auto_closure:
if (Attributes.isInOut()) {
// Verify that we're not combining this attribute incorrectly. Cannot be
// both inout and auto_closure.
diagnose(Loc, diag::cannot_combine_attribute, "inout");
Attributes.clearAttribute(attr);
}
break;
// 'cc' attribute. // 'cc' attribute.
// FIXME: only permit this in type contexts. // FIXME: only permit this in type contexts.
case AttrName::cc: { case AK_cc: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.hasCC())
diagnose(Loc, diag::duplicate_attribute);
// Parse the cc name in parens. // Parse the cc name in parens.
SourceLoc beginLoc = Tok.getLoc(), nameLoc, endLoc; SourceLoc beginLoc = Tok.getLoc(), nameLoc, endLoc;
@@ -309,166 +270,39 @@ bool Parser::parseAttribute(DeclAttributes &Attributes, unsigned KindMask,
return false; return false;
} }
case AttrName::class_protocol: { case AK_prefix:
auto Loc = consumeToken(tok::identifier); if (Attributes.isPostfix()) {
if (Attributes.isClassProtocol())
diagnose(Loc, diag::duplicate_attribute);
Attributes.ClassProtocol = true;
return false;
}
// 'objc_block' attribute.
// FIXME: only permit this in type contexts.
case AttrName::objc_block: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.ObjCBlock)
diagnose(Loc, diag::duplicate_attribute);
Attributes.ObjCBlock = true;
return false;
}
// FIXME: Only valid on var and tuple elements, not on func's, typealias, etc.
case AttrName::auto_closure: {
SourceLoc Loc = consumeToken(tok::identifier);
if (Attributes.isAutoClosure())
diagnose(Loc, diag::duplicate_attribute);
else if (Attributes.isInOut()) {
// Verify that we're not combining this attribute incorrectly. Cannot be
// both inout and auto_closure.
diagnose(Loc, diag::cannot_combine_attribute, "inout");
} else {
Attributes.AutoClosure = true;
}
return false;
}
case AttrName::thin: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.isThin())
diagnose(Loc, diag::duplicate_attribute);
else
Attributes.Thin = true;
return false;
}
case AttrName::noreturn: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.isNoReturn())
diagnose(Loc, diag::duplicate_attribute);
else
Attributes.NoReturn = true;
return false;
}
case AttrName::assignment: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.isAssignment())
diagnose(Loc, diag::duplicate_attribute);
Attributes.Assignment = true;
return false;
}
case AttrName::prefix: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.isPrefix())
diagnose(Loc, diag::duplicate_attribute);
else if (Attributes.isPostfix())
diagnose(Loc, diag::cannot_combine_attribute, "postfix"); diagnose(Loc, diag::cannot_combine_attribute, "postfix");
else Attributes.clearAttribute(attr);
Attributes.ExplicitPrefix = true; }
return false; break;
}
case AttrName::postfix: { case AK_postfix:
SourceLoc Loc = consumeToken(tok::identifier); if (Attributes.isPrefix()) {
if (Attributes.isPostfix())
diagnose(Loc, diag::duplicate_attribute);
else if (Attributes.isPrefix())
diagnose(Loc, diag::cannot_combine_attribute, "prefix"); diagnose(Loc, diag::cannot_combine_attribute, "prefix");
else Attributes.clearAttribute(attr);
Attributes.ExplicitPostfix = true; }
return false; break;
}
case AttrName::conversion: {
auto Loc = consumeToken(tok::identifier);
if (Attributes.isConversion())
diagnose(Loc, diag::duplicate_attribute);
else
Attributes.Conversion = true;
return false;
}
case AttrName::exported: {
if (Attributes.isExported())
diagnose(Tok, diag::duplicate_attribute);
consumeToken(tok::identifier);
Attributes.Exported = true;
return false;
}
case AttrName::transparent: {
if (Attributes.isTransparent())
diagnose(Tok, diag::duplicate_attribute);
consumeToken(tok::identifier);
Attributes.Transparent = true;
return false;
}
case AttrName::iboutlet: {
if (Attributes.isIBOutlet())
diagnose(Tok, diag::duplicate_attribute);
consumeToken(tok::identifier);
Attributes.IBOutlet = true;
return false;
}
case AttrName::ibaction: {
if (Attributes.isIBAction())
diagnose(Tok, diag::duplicate_attribute);
consumeToken(tok::identifier);
Attributes.IBAction = true;
return false;
}
case AttrName::objc: {
if (Attributes.isObjC())
diagnose(Tok, diag::duplicate_attribute);
consumeToken(tok::identifier);
Attributes.ObjC = true;
return false;
}
/// FIXME: This is a temporary hack until we can import C modules.
case AttrName::asmname: {
SourceLoc TokLoc = Tok.getLoc();
if (!Attributes.AsmName.empty())
diagnose(Tok, diag::duplicate_attribute);
consumeToken(tok::identifier);
case AK_asmname: {
if (!consumeIf(tok::equal)) { if (!consumeIf(tok::equal)) {
diagnose(TokLoc, diag::asmname_expected_equals); diagnose(Loc, diag::asmname_expected_equals);
Attributes.clearAttribute(attr);
return false; return false;
} }
if (!Tok.is(tok::string_literal)) { if (Tok.isNot(tok::string_literal)) {
diagnose(TokLoc, diag::asmname_expected_string_literal); diagnose(Loc, diag::asmname_expected_string_literal);
return false; Attributes.clearAttribute(attr);
return false;
} }
SmallVector<Lexer::StringSegment, 1> Segments; SmallVector<Lexer::StringSegment, 1> Segments;
L->getStringLiteralSegments(Tok, Segments); L->getStringLiteralSegments(Tok, Segments);
if (Segments.size() != 1 || if (Segments.size() != 1 ||
Segments.front().Kind == Lexer::StringSegment::Expr) { Segments.front().Kind == Lexer::StringSegment::Expr) {
diagnose(TokLoc, diag::asmname_interpolated_string); diagnose(Loc, diag::asmname_interpolated_string);
Attributes.clearAttribute(attr);
} else { } else {
Attributes.AsmName = StringRef( Attributes.AsmName = StringRef(
SourceMgr->getMemoryBuffer(BufferID)->getBufferStart() + SourceMgr->getMemoryBuffer(BufferID)->getBufferStart() +
@@ -476,68 +310,31 @@ bool Parser::parseAttribute(DeclAttributes &Attributes, unsigned KindMask,
Segments.front().Length); Segments.front().Length);
} }
consumeToken(tok::string_literal); consumeToken(tok::string_literal);
return false; break;
} }
case AttrName::kernel: { case AK_kernel:
case AK_vertex:
case AK_fragment:
// Reject Axle specific attributes in non-axle mode.
if (!Context.LangOpts.Axle) { if (!Context.LangOpts.Axle) {
diagnose(Tok, diag::invalid_attribute_for_lang, Tok.getText(), diagnose(Loc, diag::invalid_attribute_for_lang,
0 /* axle */); 0 /* axle */);
consumeToken(tok::identifier); Attributes.clearAttribute(attr);
return false; return false;
} }
if (Attributes.isKernel())
diagnose(Tok, diag::duplicate_attribute);
if (Attributes.isVertex())
diagnose(Tok, diag::cannot_combine_attribute, "vertex");
if (Attributes.isFragment())
diagnose(Tok, diag::cannot_combine_attribute, "fragment");
consumeToken(tok::identifier); // Check multiple specifications by temporarily removing this attribute.
Attributes.KernelOrShader = KernelOrShaderKind::Kernel; Attributes.clearAttribute(attr);
return false; if (Attributes.getKernelOrShaderKind() != KernelOrShaderKind::Default) {
} diagnose(Loc, diag::duplicate_attribute);
break;
case AttrName::vertex: {
if (!Context.LangOpts.Axle) {
diagnose(Tok, diag::invalid_attribute_for_lang, Tok.getText(),
0 /* axle */);
consumeToken(tok::identifier);
return false;
} }
if (Attributes.isVertex()) Attributes.setAttr(attr, Loc);
diagnose(Tok, diag::duplicate_attribute); break;
if (Attributes.isKernel())
diagnose(Tok, diag::cannot_combine_attribute, "kernel");
if (Attributes.isFragment())
diagnose(Tok, diag::cannot_combine_attribute, "fragment");
consumeToken(tok::identifier);
Attributes.KernelOrShader = KernelOrShaderKind::Vertex;
return false;
} }
case AttrName::fragment: { return false;
if (!Context.LangOpts.Axle) {
diagnose(Tok, diag::invalid_attribute_for_lang, Tok.getText(),
0 /* axle */);
consumeToken(tok::identifier);
return false;
}
if (Attributes.isFragment())
diagnose(Tok, diag::duplicate_attribute);
if (Attributes.isKernel())
diagnose(Tok, diag::cannot_combine_attribute, "kernel");
if (Attributes.isVertex())
diagnose(Tok, diag::cannot_combine_attribute, "vertex");
consumeToken(tok::identifier);
Attributes.KernelOrShader = KernelOrShaderKind::Fragment;
return false;
}
}
llvm_unreachable("bad attribute kind");
} }
/// \brief This is the internal implementation of \c parseAttributeList, which /// \brief This is the internal implementation of \c parseAttributeList, which
@@ -799,15 +596,11 @@ ParserResult<ImportDecl> Parser::parseDeclImport(unsigned Flags,
DeclAttributes &Attributes) { DeclAttributes &Attributes) {
SourceLoc ImportLoc = consumeToken(tok::kw_import); SourceLoc ImportLoc = consumeToken(tok::kw_import);
bool Exported; parseAttributeList(Attributes, AK_DeclAttributes, true);
{ bool Exported = Attributes.isExported();
parseAttributeList(Attributes, AK_DeclAttributes, true); Attributes.clearAttribute(AK_exported);
if (!Attributes.empty())
Exported = Attributes.isExported(); diagnose(Attributes.AtLoc, diag::import_attributes);
Attributes.Exported = false;
if (!Attributes.empty())
diagnose(Attributes.AtLoc, diag::import_attributes);
}
if (!(Flags & PD_AllowTopLevel)) { if (!(Flags & PD_AllowTopLevel)) {
diagnose(ImportLoc, diag::decl_inner_scope); diagnose(ImportLoc, diag::decl_inner_scope);

View File

@@ -625,13 +625,14 @@ bool SILParser::parseSILType(SILType &Result) {
P.parseAttributeList(attrs, Parser::AK_SILAttributes, false); P.parseAttributeList(attrs, Parser::AK_SILAttributes, false);
P.parseAttributeList(attrs, Parser::AK_SILAttributes, true); P.parseAttributeList(attrs, Parser::AK_SILAttributes, true);
// Handle [local_storage], which changes the SIL value category. // Handle @local_storage, which changes the SIL value category.
if (attrs.isLocalStorage()) { if (attrs.isLocalStorage()) {
// Require '*' on local_storage values. // Require '*' on local_storage values.
if (category != SILValueCategory::Address) if (category != SILValueCategory::Address)
P.diagnose(attrs.AtLoc, diag::sil_local_storage_non_address); P.diagnose(attrs.getLoc(AK_local_storage),
diag::sil_local_storage_non_address);
category = SILValueCategory::LocalStorage; category = SILValueCategory::LocalStorage;
attrs.LocalStorage = false; attrs.clearAttribute(AK_local_storage);
} }
// Parse Generic Parameters. Generic Parameters are visible in the function // Parse Generic Parameters. Generic Parameters are visible in the function
@@ -665,7 +666,8 @@ bool SILParser::parseSILType(SILType &Result) {
P.Context); P.Context);
Ty.setType(resultType); Ty.setType(resultType);
// Reset attributes that are applied. // Reset attributes that are applied.
attrs.Thin = false; attrs.clearAttribute(AK_thin);
attrs.clearAttribute(AK_cc);
attrs.cc = Nothing; attrs.cc = Nothing;
} }

View File

@@ -1145,7 +1145,7 @@ public:
ProtocolDecl *protocolContext = dyn_cast<ProtocolDecl>(dc); ProtocolDecl *protocolContext = dyn_cast<ProtocolDecl>(dc);
bool isObjC = (classContext && classContext->isObjC()) bool isObjC = (classContext && classContext->isObjC())
|| (protocolContext && protocolContext->isObjC()) || (protocolContext && protocolContext->isObjC())
|| SD->getAttrs().ObjC; || SD->getAttrs().isObjC();
if (isObjC && SD->getObjCSubscriptKind() != ObjCSubscriptKind::None) { if (isObjC && SD->getObjCSubscriptKind() != ObjCSubscriptKind::None) {
SD->setIsObjC(true); SD->setIsObjC(true);
} }
@@ -1440,32 +1440,29 @@ public:
auto Info = AnyFunctionType::ExtInfo(); auto Info = AnyFunctionType::ExtInfo();
if (Attrs.hasCC()) { if (Attrs.hasCC()) {
TC.diagnose(FD->getStartLoc(), diag::invalid_decl_attribute, "cc"); TC.diagnose(Attrs.getLoc(AK_cc), diag::invalid_decl_attribute);
Attrs.cc = {}; Attrs.cc = {};
Attrs.clearAttribute(AK_cc);
} }
if (Attrs.isThin()) { if (Attrs.isThin()) {
TC.diagnose(FD->getStartLoc(), diag::invalid_decl_attribute, TC.diagnose(Attrs.getLoc(AK_thin), diag::invalid_decl_attribute);
"thin"); Attrs.clearAttribute(AK_thin);
Attrs.Thin = false;
} }
// 'noreturn' is allowed on a function declaration. // 'noreturn' is allowed on a function declaration.
Info = Info.withIsNoReturn(Attrs.isNoReturn()); Info = Info.withIsNoReturn(Attrs.isNoReturn());
if (consumeAttributes) { if (consumeAttributes)
Attrs.NoReturn = false; Attrs.clearAttribute(AK_noreturn);
}
if (Attrs.isAutoClosure()) { if (Attrs.isAutoClosure()) {
TC.diagnose(FD->getStartLoc(), diag::invalid_decl_attribute, TC.diagnose(Attrs.getLoc(AK_auto_closure), diag::invalid_decl_attribute);
"auto_closure"); Attrs.clearAttribute(AK_auto_closure);
Attrs.AutoClosure = false;
} }
if (Attrs.isObjCBlock()) { if (Attrs.isObjCBlock()) {
TC.diagnose(FD->getStartLoc(), diag::invalid_decl_attribute, TC.diagnose(Attrs.getLoc(AK_objc_block), diag::invalid_decl_attribute);
"objc_block"); Attrs.clearAttribute(AK_objc_block);
Attrs.ObjCBlock = false;
} }
return Info; return Info;
@@ -1596,13 +1593,13 @@ public:
SourceLoc insertionLoc = FD->getLoc(); SourceLoc insertionLoc = FD->getLoc();
const char *insertionText; const char *insertionText;
if (postfixOp) { if (postfixOp) {
insertionText = "[postfix] "; insertionText = "@postfix ";
op = *postfixOp; op = *postfixOp;
FD->getMutableAttrs().ExplicitPostfix = true; FD->getMutableAttrs().setAttr(AK_postfix, SourceLoc());
} else { } else {
insertionText = "[prefix] "; insertionText = "@prefix ";
op = *prefixOp; op = *prefixOp;
FD->getMutableAttrs().ExplicitPrefix = true; FD->getMutableAttrs().setAttr(AK_prefix, SourceLoc());
} }
// Emit diagnostic with the Fix-It. // Emit diagnostic with the Fix-It.
@@ -2704,7 +2701,7 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
if (error) { if (error) {
TC.diagnose(D->getStartLoc(), *error); TC.diagnose(D->getStartLoc(), *error);
D->getMutableAttrs().ObjC = false; D->getMutableAttrs().clearAttribute(AK_objc);
return; return;
} }
} }
@@ -2771,8 +2768,8 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
// FIXME: This could do some type validation as well (all IBOutlets refer // FIXME: This could do some type validation as well (all IBOutlets refer
// to objects). // to objects).
if (!(isa<VarDecl>(D) && isInClassContext(D))) { if (!(isa<VarDecl>(D) && isInClassContext(D))) {
TC.diagnose(D->getStartLoc(), diag::invalid_iboutlet); TC.diagnose(Attrs.getLoc(AK_iboutlet), diag::invalid_iboutlet);
D->getMutableAttrs().IBOutlet = false; D->getMutableAttrs().clearAttribute(AK_iboutlet);
return; return;
} }
} }
@@ -2782,8 +2779,8 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
const FuncDecl *FD = dyn_cast<FuncDecl>(D); const FuncDecl *FD = dyn_cast<FuncDecl>(D);
if (!FD || !isa<ClassDecl>(D->getDeclContext()) || FD->isStatic() || if (!FD || !isa<ClassDecl>(D->getDeclContext()) || FD->isStatic() ||
FD->isGetterOrSetter()) { FD->isGetterOrSetter()) {
TC.diagnose(D->getStartLoc(), diag::invalid_ibaction_decl); TC.diagnose(Attrs.getLoc(AK_ibaction), diag::invalid_ibaction_decl);
D->getMutableAttrs().IBAction = false; D->getMutableAttrs().clearAttribute(AK_ibaction);
return; return;
} }
@@ -2794,7 +2791,7 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
Type ResultTy = CurriedTy->castTo<AnyFunctionType>()->getResult(); Type ResultTy = CurriedTy->castTo<AnyFunctionType>()->getResult();
if (!ResultTy->isEqual(TupleType::getEmpty(TC.Context))) { if (!ResultTy->isEqual(TupleType::getEmpty(TC.Context))) {
TC.diagnose(D->getStartLoc(), diag::invalid_ibaction_result, ResultTy); TC.diagnose(D->getStartLoc(), diag::invalid_ibaction_result, ResultTy);
D->getMutableAttrs().IBAction = false; D->getMutableAttrs().clearAttribute(AK_ibaction);
return; return;
} }
} }
@@ -2818,16 +2815,16 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
if (Attrs.isPostfix()) { if (Attrs.isPostfix()) {
// Only operator functions can be postfix. // Only operator functions can be postfix.
if (!isOperator) { if (!isOperator) {
TC.diagnose(D->getStartLoc(), diag::postfix_not_an_operator); TC.diagnose(Attrs.getLoc(AK_postfix), diag::postfix_not_an_operator);
D->getMutableAttrs().ExplicitPostfix = false; D->getMutableAttrs().clearAttribute(AK_postfix);
// FIXME: Set the 'isError' bit on the decl. // FIXME: Set the 'isError' bit on the decl.
return; return;
} }
// Only unary operators can be postfix. // Only unary operators can be postfix.
if (!FDOrNull || !FDOrNull->isUnaryOperator()) { if (!FDOrNull || !FDOrNull->isUnaryOperator()) {
TC.diagnose(D->getStartLoc(), diag::invalid_postfix_input); TC.diagnose(Attrs.getLoc(AK_postfix), diag::invalid_postfix_input);
D->getMutableAttrs().ExplicitPostfix = false; D->getMutableAttrs().clearAttribute(AK_postfix);
// FIXME: Set the 'isError' bit on the decl. // FIXME: Set the 'isError' bit on the decl.
return; return;
} }
@@ -2836,16 +2833,16 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
if (Attrs.isPrefix()) { if (Attrs.isPrefix()) {
// Only operator functions can be postfix. // Only operator functions can be postfix.
if (!isOperator) { if (!isOperator) {
TC.diagnose(D->getStartLoc(), diag::prefix_not_an_operator); TC.diagnose(Attrs.getLoc(AK_prefix), diag::prefix_not_an_operator);
D->getMutableAttrs().ExplicitPostfix = false; D->getMutableAttrs().clearAttribute(AK_prefix);
// FIXME: Set the 'isError' bit on the decl. // FIXME: Set the 'isError' bit on the decl.
return; return;
} }
// Only unary operators can be postfix. // Only unary operators can be postfix.
if (!FDOrNull || !FDOrNull->isUnaryOperator()) { if (!FDOrNull || !FDOrNull->isUnaryOperator()) {
TC.diagnose(D->getStartLoc(), diag::invalid_prefix_input); TC.diagnose(Attrs.getLoc(AK_prefix), diag::invalid_prefix_input);
D->getMutableAttrs().ExplicitPostfix = false; D->getMutableAttrs().clearAttribute(AK_prefix);
// FIXME: Set the 'isError' bit on the decl. // FIXME: Set the 'isError' bit on the decl.
return; return;
} }
@@ -2855,11 +2852,11 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
// Only function declarations can be assignments. // Only function declarations can be assignments.
FuncDecl *FD = dyn_cast<FuncDecl>(D); FuncDecl *FD = dyn_cast<FuncDecl>(D);
if (!FD || !FD->isOperator()) { if (!FD || !FD->isOperator()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute,"assignment"); TC.diagnose(Attrs.getLoc(AK_assignment), diag::invalid_decl_attribute);
D->getMutableAttrs().Assignment = false; D->getMutableAttrs().clearAttribute(AK_assignment);
} else if (NumArguments < 1) { } else if (NumArguments < 1) {
TC.diagnose(D->getStartLoc(), diag::assignment_without_inout); TC.diagnose(Attrs.getLoc(AK_assignment),diag::assignment_without_inout);
D->getMutableAttrs().Assignment = false; D->getMutableAttrs().clearAttribute(AK_assignment);
} else { } else {
auto FT = FD->getType()->castTo<AnyFunctionType>(); auto FT = FD->getType()->castTo<AnyFunctionType>();
Type ParamType = FT->getInput(); Type ParamType = FT->getInput();
@@ -2868,8 +2865,9 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
ParamType = ParamTT->getElementType(0); ParamType = ParamTT->getElementType(0);
if (!ParamType->is<LValueType>()) { if (!ParamType->is<LValueType>()) {
TC.diagnose(D->getStartLoc(), diag::assignment_without_inout); TC.diagnose(Attrs.getLoc(AK_assignment),
D->getMutableAttrs().Assignment = false; diag::assignment_without_inout);
D->getMutableAttrs().clearAttribute(AK_assignment);
} }
} }
} }
@@ -2879,12 +2877,12 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
// conversions. // conversions.
FuncDecl *FD = dyn_cast<FuncDecl>(D); FuncDecl *FD = dyn_cast<FuncDecl>(D);
if (!FD) { if (!FD) {
TC.diagnose(D->getStartLoc(), diag::conversion_not_function); TC.diagnose(Attrs.getLoc(AK_conversion), diag::conversion_not_function);
D->getMutableAttrs().Conversion = false; D->getMutableAttrs().clearAttribute(AK_conversion);
} else if (!FD->isInstanceMember()) { } else if (!FD->isInstanceMember()) {
TC.diagnose(FD->getStartLoc(), diag::conversion_not_instance_method, TC.diagnose(Attrs.getLoc(AK_conversion),
FD->getName()); diag::conversion_not_instance_method, FD->getName());
FD->getMutableAttrs().Conversion = false; D->getMutableAttrs().clearAttribute(AK_conversion);
} else if (!FD->getType()->is<ErrorType>()) { } else if (!FD->getType()->is<ErrorType>()) {
AnyFunctionType *BoundMethodTy AnyFunctionType *BoundMethodTy
= FD->getType()->castTo<AnyFunctionType>()->getResult() = FD->getType()->castTo<AnyFunctionType>()->getResult()
@@ -2905,9 +2903,9 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
} }
if (!AcceptsEmptyParamList) { if (!AcceptsEmptyParamList) {
TC.diagnose(FD->getStartLoc(), diag::conversion_params, TC.diagnose(Attrs.getLoc(AK_conversion), diag::conversion_params,
FD->getName()); FD->getName());
D->getMutableAttrs().Conversion = false; D->getMutableAttrs().clearAttribute(AK_conversion);
} }
} }
} }
@@ -2918,96 +2916,72 @@ static void validateAttributes(TypeChecker &TC, Decl *D) {
auto *ED = dyn_cast<ExtensionDecl>(D); auto *ED = dyn_cast<ExtensionDecl>(D);
if (!AFD && !ED) { if (!AFD && !ED) {
TC.diagnose(D->getStartLoc(), diag::transparent_not_valid); TC.diagnose(Attrs.getLoc(AK_transparent), diag::transparent_not_valid);
D->getMutableAttrs().Transparent = false; D->getMutableAttrs().clearAttribute(AK_transparent);
// Only Struct and Enum extensions can be transparent. // Only Struct and Enum extensions can be transparent.
} else if (ED) { } else if (ED) {
CanType ExtendedTy = getExtendedType(ED); CanType ExtendedTy = getExtendedType(ED);
if (!isa<StructType>(ExtendedTy) && !isa<EnumType>(ExtendedTy)) { if (!isa<StructType>(ExtendedTy) && !isa<EnumType>(ExtendedTy)) {
TC.diagnose(D->getStartLoc(), diag::transparent_on_invalid_extension); TC.diagnose(Attrs.getLoc(AK_transparent),
D->getMutableAttrs().Transparent = false; diag::transparent_on_invalid_extension);
D->getMutableAttrs().clearAttribute(AK_transparent);
} }
} else if (AFD->getGenericParams()) { } else if (AFD->getGenericParams()) {
// FIXME: We don't yet support transparent on generic functions. // FIXME: We don't yet support transparent on generic functions.
TC.diagnose(D->getStartLoc(), diag::transparent_generic_not_supported); TC.diagnose(Attrs.getLoc(AK_transparent),
D->getMutableAttrs().Transparent = false; diag::transparent_generic_not_supported);
D->getMutableAttrs().clearAttribute(AK_transparent);
// Protocol method declarations cannot be transparent. // Protocol method declarations cannot be transparent.
} else if (isa<ProtocolDecl>(AFD->getParent())) { } else if (isa<ProtocolDecl>(AFD->getParent())) {
TC.diagnose(D->getStartLoc(), TC.diagnose(Attrs.getLoc(AK_transparent),
diag::transparent_in_protocols_not_supported); diag::transparent_in_protocols_not_supported);
D->getMutableAttrs().Transparent = false; D->getMutableAttrs().clearAttribute(AK_transparent);
// Class methods cannot be transparent. // Class methods cannot be transparent.
} else if (isa<ClassDecl>(AFD->getParent())) { } else if (isa<ClassDecl>(AFD->getParent())) {
TC.diagnose(D->getStartLoc(), TC.diagnose(Attrs.getLoc(AK_transparent),
diag::transparent_in_classes_not_supported); diag::transparent_in_classes_not_supported);
D->getMutableAttrs().Transparent = false; D->getMutableAttrs().clearAttribute(AK_transparent);
} }
} }
if (Attrs.isInOut()) { static const AttrKind InvalidAttrs[] = {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "inout"); AK_inout, AK_auto_closure,
D->getMutableAttrs().InOut = false; AK_exported, AK_objc_block, AK_cc, AK_thin, AK_noreturn, AK_local_storage
} };
if (Attrs.isAutoClosure()) { for (AttrKind K : InvalidAttrs) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "auto_closure"); if (Attrs.has(K)) {
D->getMutableAttrs().AutoClosure = false; TC.diagnose(Attrs.getLoc(K), diag::invalid_decl_attribute);
} D->getMutableAttrs().clearAttribute(K);
}
if (Attrs.isExported()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "exported");
D->getMutableAttrs().Exported = false;
}
if (Attrs.isObjCBlock()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "objc_block");
D->getMutableAttrs().ObjCBlock = false;
} }
// Only protocols can have the [class_protocol] attribute. // Only protocols can have the [class_protocol] attribute.
if (Attrs.isClassProtocol() && !isa<ProtocolDecl>(D)) { if (Attrs.isClassProtocol() && !isa<ProtocolDecl>(D)) {
TC.diagnose(D->getStartLoc(), diag::class_protocol_not_protocol); TC.diagnose(Attrs.getLoc(AK_class_protocol),
D->getMutableAttrs().ClassProtocol = false; diag::class_protocol_not_protocol);
D->getMutableAttrs().clearAttribute(AK_class_protocol);
} }
if (Attrs.hasCC()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "cc");
D->getMutableAttrs().cc = {};
}
if (Attrs.isThin()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "thin");
D->getMutableAttrs().Thin = false;
}
if (Attrs.isNoReturn()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "noreturn");
D->getMutableAttrs().NoReturn = false;
}
if (Attrs.isLocalStorage()) {
TC.diagnose(D->getStartLoc(), diag::invalid_decl_attribute, "local_storage");
D->getMutableAttrs().LocalStorage = false;
}
if (!isa<FuncDecl>(D)) { if (!isa<FuncDecl>(D)) {
if (Attrs.isKernel()) { if (Attrs.isKernel()) {
TC.diagnose(D->getStartLoc(), diag::attribute_requires_function_decl, TC.diagnose(D->getStartLoc(), diag::attribute_requires_function_decl,
"kernel"); "kernel");
D->getMutableAttrs().KernelOrShader = KernelOrShaderKind::Default; D->getMutableAttrs().clearAttribute(AK_kernel);
} }
if (Attrs.isVertex()) { if (Attrs.isVertex()) {
TC.diagnose(D->getStartLoc(), diag::attribute_requires_function_decl, TC.diagnose(D->getStartLoc(), diag::attribute_requires_function_decl,
"vertex"); "vertex");
D->getMutableAttrs().KernelOrShader = KernelOrShaderKind::Default; D->getMutableAttrs().clearAttribute(AK_vertex);
} }
if (Attrs.isFragment()) { if (Attrs.isFragment()) {
TC.diagnose(D->getStartLoc(), diag::attribute_requires_function_decl, TC.diagnose(D->getStartLoc(), diag::attribute_requires_function_decl,
"fragment"); "fragment");
D->getMutableAttrs().KernelOrShader = KernelOrShaderKind::Default; D->getMutableAttrs().clearAttribute(AK_fragment);
} }
} }
} }

View File

@@ -613,16 +613,16 @@ Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC,
if (auto protoTy = Ty->getAs<ProtocolType>()) { if (auto protoTy = Ty->getAs<ProtocolType>()) {
Ty = protoTy->getDecl()->getSelf()->getArchetype(); Ty = protoTy->getDecl()->getSelf()->getArchetype();
} else { } else {
diagnose(attrs.AtLoc, diag::sil_self_non_protocol, Ty) diagnose(attrs.getLoc(AK_sil_self), diag::sil_self_non_protocol, Ty)
.highlight(AttrTyR->getTypeRepr()->getSourceRange()); .highlight(AttrTyR->getTypeRepr()->getSourceRange());
} }
attrs.SILSelf = false; attrs.clearAttribute(AK_sil_self);
} }
if (attrs.isInOut()) { if (attrs.isInOut()) {
LValueType::Qual quals; LValueType::Qual quals;
Ty = LValueType::get(Ty, quals, Context); Ty = LValueType::get(Ty, quals, Context);
attrs.InOut = false; // so that the empty() check below works attrs.clearAttribute(AK_inout);
} }
// Handle the auto_closure, cc, and objc_block attributes for function types. // Handle the auto_closure, cc, and objc_block attributes for function types.
@@ -677,12 +677,15 @@ Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC,
Info, Info,
Context); Context);
} }
attrs.AutoClosure = false; attrs.clearAttribute(AK_auto_closure);
attrs.ObjCBlock = false; attrs.clearAttribute(AK_objc_block);
attrs.Thin = false; attrs.clearAttribute(AK_thin);
attrs.NoReturn = false; attrs.clearAttribute(AK_noreturn);
attrs.clearAttribute(AK_cc);
attrs.cc = Nothing; attrs.cc = Nothing;
attrs.KernelOrShader = KernelOrShaderKind::Default; attrs.clearAttribute(AK_kernel);
attrs.clearAttribute(AK_fragment);
attrs.clearAttribute(AK_vertex);
} }
// In SIL translation units *only*, permit [weak] and [unowned] to // In SIL translation units *only*, permit [weak] and [unowned] to
@@ -699,8 +702,8 @@ Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC,
if (attrs.isLocalStorage()) { if (attrs.isLocalStorage()) {
assert(cast<TranslationUnit>(DC->getParentModule()) assert(cast<TranslationUnit>(DC->getParentModule())
->MainSourceFile->Kind == SourceFile::SIL); ->MainSourceFile->Kind == SourceFile::SIL);
diagnose(attrs.AtLoc, diag::sil_local_storage_nested); diagnose(attrs.getLoc(AK_local_storage),diag::sil_local_storage_nested);
attrs.LocalStorage = false; attrs.clearAttribute(AK_local_storage);
} }
// FIXME: this is lame. // FIXME: this is lame.

View File

@@ -1066,7 +1066,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
var->setImplicit(); var->setImplicit();
var->setIsObjC(isObjC); var->setIsObjC(isObjC);
if (isIBOutlet) if (isIBOutlet)
var->getMutableAttrs().IBOutlet = true; var->getMutableAttrs().setAttr(AK_iboutlet, SourceLoc());
var->setOverriddenDecl(cast_or_null<VarDecl>(getDecl(overriddenID))); var->setOverriddenDecl(cast_or_null<VarDecl>(getDecl(overriddenID)));
break; break;
@@ -1149,24 +1149,24 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
fn->getMutableAttrs().AsmName = ctx.AllocateCopy(blobData); fn->getMutableAttrs().AsmName = ctx.AllocateCopy(blobData);
if (isAssignmentOrConversion) { if (isAssignmentOrConversion) {
if (fn->isOperator()) if (fn->isOperator())
fn->getMutableAttrs().Assignment = true; fn->getMutableAttrs().setAttr(AK_assignment, SourceLoc());
else else
fn->getMutableAttrs().Conversion = true; fn->getMutableAttrs().setAttr(AK_conversion, SourceLoc());
} }
fn->setIsObjC(isObjC); fn->setIsObjC(isObjC);
if (isIBAction) if (isIBAction)
fn->getMutableAttrs().IBAction = true; fn->getMutableAttrs().setAttr(AK_ibaction, SourceLoc());
if (isTransparent) if (isTransparent)
fn->getMutableAttrs().Transparent = true; fn->getMutableAttrs().setAttr(AK_transparent, SourceLoc());
if (Decl *associated = getDecl(associatedDeclID)) { if (Decl *associated = getDecl(associatedDeclID)) {
if (auto op = dyn_cast<OperatorDecl>(associated)) { if (auto op = dyn_cast<OperatorDecl>(associated)) {
fn->setOperatorDecl(op); fn->setOperatorDecl(op);
if (isa<PrefixOperatorDecl>(op)) if (isa<PrefixOperatorDecl>(op))
fn->getMutableAttrs().ExplicitPrefix = true; fn->getMutableAttrs().setAttr(AK_prefix, SourceLoc());
else if (isa<PostfixOperatorDecl>(op)) else if (isa<PostfixOperatorDecl>(op))
fn->getMutableAttrs().ExplicitPostfix = true; fn->getMutableAttrs().setAttr(AK_postfix, SourceLoc());
// Note that an explicit [infix] is not required. // Note that an explicit [infix] is not required.
} }
// Otherwise, unknown associated decl kind. // Otherwise, unknown associated decl kind.
@@ -1238,7 +1238,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
if (isImplicit) if (isImplicit)
proto->setImplicit(); proto->setImplicit();
if (isClassProtocol) if (isClassProtocol)
proto->getMutableAttrs().ClassProtocol = true; proto->getMutableAttrs().setAttr(AK_class_protocol, SourceLoc());
proto->setIsObjC(isObjC); proto->setIsObjC(isObjC);
proto->computeType(); proto->computeType();

View File

@@ -1149,7 +1149,7 @@ void Serializer::writeDecl(const Decl *D) {
auto theClass = cast<ClassDecl>(D); auto theClass = cast<ClassDecl>(D);
DeclAttributes remainingAttrs = theClass->getAttrs(); DeclAttributes remainingAttrs = theClass->getAttrs();
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_objc);
assert(remainingAttrs.empty() && "unhandled class attrs"); assert(remainingAttrs.empty() && "unhandled class attrs");
const Decl *DC = getDeclForContext(theClass->getDeclContext()); const Decl *DC = getDeclForContext(theClass->getDeclContext());
@@ -1175,8 +1175,8 @@ void Serializer::writeDecl(const Decl *D) {
auto proto = cast<ProtocolDecl>(D); auto proto = cast<ProtocolDecl>(D);
DeclAttributes remainingAttrs = proto->getAttrs(); DeclAttributes remainingAttrs = proto->getAttrs();
remainingAttrs.ClassProtocol = false; remainingAttrs.clearAttribute(AK_class_protocol);
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_objc);
assert(remainingAttrs.empty() && "unhandled protocol attrs"); assert(remainingAttrs.empty() && "unhandled protocol attrs");
@@ -1206,8 +1206,8 @@ void Serializer::writeDecl(const Decl *D) {
DeclAttributes remainingAttrs = var->getAttrs(); DeclAttributes remainingAttrs = var->getAttrs();
// FIXME: We need some representation of these for source fidelity. // FIXME: We need some representation of these for source fidelity.
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_objc);
remainingAttrs.IBOutlet = false; remainingAttrs.clearAttribute(AK_iboutlet);
assert(remainingAttrs.empty() && "unhandled var attrs"); assert(remainingAttrs.empty() && "unhandled var attrs");
@@ -1233,17 +1233,18 @@ void Serializer::writeDecl(const Decl *D) {
DeclAttributes remainingAttrs = fn->getAttrs(); DeclAttributes remainingAttrs = fn->getAttrs();
// FIXME: We need some representation of these for source fidelity. // FIXME: We need some representation of these for source fidelity.
remainingAttrs.ExplicitPrefix = false; remainingAttrs.clearAttribute(AK_prefix);
remainingAttrs.ExplicitPostfix = false; remainingAttrs.clearAttribute(AK_postfix);
remainingAttrs.ExplicitInfix = false; remainingAttrs.clearAttribute(AK_infix);
remainingAttrs.Assignment = false; remainingAttrs.clearAttribute(AK_assignment);
remainingAttrs.Conversion = false; remainingAttrs.clearAttribute(AK_conversion);
remainingAttrs.AsmName = {}; remainingAttrs.AsmName = {};
remainingAttrs.NoReturn = false; remainingAttrs.clearAttribute(AK_asmname);
remainingAttrs.Thin = false; remainingAttrs.clearAttribute(AK_noreturn);
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_thin);
remainingAttrs.IBAction = false; remainingAttrs.clearAttribute(AK_objc);
remainingAttrs.Transparent = false; remainingAttrs.clearAttribute(AK_ibaction);
remainingAttrs.clearAttribute(AK_transparent);
assert(remainingAttrs.empty() && "unhandled func attrs"); assert(remainingAttrs.empty() && "unhandled func attrs");
@@ -1306,7 +1307,7 @@ void Serializer::writeDecl(const Decl *D) {
auto subscript = cast<SubscriptDecl>(D); auto subscript = cast<SubscriptDecl>(D);
DeclAttributes remainingAttrs = subscript->getAttrs(); DeclAttributes remainingAttrs = subscript->getAttrs();
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_objc);
assert(remainingAttrs.empty() && "unhandled subscript attrs"); assert(remainingAttrs.empty() && "unhandled subscript attrs");
const Decl *DC = getDeclForContext(subscript->getDeclContext()); const Decl *DC = getDeclForContext(subscript->getDeclContext());
@@ -1331,8 +1332,8 @@ void Serializer::writeDecl(const Decl *D) {
auto ctor = cast<ConstructorDecl>(D); auto ctor = cast<ConstructorDecl>(D);
DeclAttributes remainingAttrs = ctor->getAttrs(); DeclAttributes remainingAttrs = ctor->getAttrs();
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_objc);
remainingAttrs.Transparent = false; remainingAttrs.clearAttribute(AK_transparent);
assert(remainingAttrs.empty() && "unhandled constructor attrs"); assert(remainingAttrs.empty() && "unhandled constructor attrs");
@@ -1359,7 +1360,7 @@ void Serializer::writeDecl(const Decl *D) {
auto dtor = cast<DestructorDecl>(D); auto dtor = cast<DestructorDecl>(D);
DeclAttributes remainingAttrs = dtor->getAttrs(); DeclAttributes remainingAttrs = dtor->getAttrs();
remainingAttrs.ObjC = false; remainingAttrs.clearAttribute(AK_objc);
assert(remainingAttrs.empty() && "unhandled destructor attrs"); assert(remainingAttrs.empty() && "unhandled destructor attrs");
const Decl *DC = getDeclForContext(dtor->getDeclContext()); const Decl *DC = getDeclForContext(dtor->getDeclContext());