mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
285 lines
8.7 KiB
C++
285 lines
8.7 KiB
C++
//===--- Attr.h - Swift Language Attribute ASTs -----------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines classes related to declaration attributes.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_ATTR_H
|
|
#define SWIFT_ATTR_H
|
|
|
|
#include "swift/Basic/Optional.h"
|
|
#include "swift/Basic/SourceLoc.h"
|
|
#include "swift/AST/Ownership.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
namespace swift {
|
|
|
|
/// The associativity of a binary operator.
|
|
enum class Associativity {
|
|
/// Non-associative operators cannot be written next to other
|
|
/// operators with the same precedence. Relational operators are
|
|
/// typically non-associative.
|
|
None,
|
|
|
|
/// Left-associative operators associate to the left if written next
|
|
/// to other left-associative operators of the same precedence.
|
|
Left,
|
|
|
|
/// Right-associative operators associate to the right if written
|
|
/// next to other right-associative operators of the same precedence.
|
|
Right
|
|
};
|
|
|
|
class InfixData {
|
|
unsigned Precedence : 8;
|
|
|
|
/// Zero if invalid, or else an Associativity+1.
|
|
unsigned InvalidOrAssoc : 8;
|
|
public:
|
|
InfixData() : Precedence(0), InvalidOrAssoc(0) {}
|
|
InfixData(unsigned char prec, Associativity assoc)
|
|
: Precedence(prec), InvalidOrAssoc(unsigned(assoc) + 1) {}
|
|
|
|
bool isValid() const { return InvalidOrAssoc != 0; }
|
|
|
|
Associativity getAssociativity() const {
|
|
assert(isValid());
|
|
return Associativity(InvalidOrAssoc - 1);
|
|
}
|
|
bool isLeftAssociative() const {
|
|
return getAssociativity() == Associativity::Left;
|
|
}
|
|
bool isRightAssociative() const {
|
|
return getAssociativity() == Associativity::Right;
|
|
}
|
|
bool isNonAssociative() const {
|
|
return getAssociativity() == Associativity::None;
|
|
}
|
|
|
|
unsigned getPrecedence() const {
|
|
assert(isValid());
|
|
return Precedence;
|
|
}
|
|
|
|
friend bool operator==(InfixData L, InfixData R) {
|
|
return L.Precedence == R.Precedence
|
|
&& L.InvalidOrAssoc == R.InvalidOrAssoc;
|
|
}
|
|
friend bool operator!=(InfixData L, InfixData R) {
|
|
return !operator==(L, R);
|
|
}
|
|
};
|
|
|
|
/// ABI resilience. Language structures are resilient if the details
|
|
/// of their implementation may be changed without requiring
|
|
/// associated code to be reprocessed. Different structures are resilient
|
|
/// in different ways. For example:
|
|
/// - A resilient type does not have a statically fixed size or layout.
|
|
/// - A resilient variable must be accessed with getters and setters, even if
|
|
/// none are defined for it now.
|
|
/// - A resilient function may not be inlined.
|
|
///
|
|
/// In general, resilience is inherited from the lexical context. For
|
|
/// example, a variable declared in a fragile struct is implicitly fragile.
|
|
///
|
|
/// Some language structures, like tuples, are never themselves
|
|
/// resilient (although they may be defined in terms of resilient
|
|
/// types). Additionally, code distributed with the component
|
|
/// defining a resilient structure need not actually use resilience
|
|
/// boundaries.
|
|
enum class Resilience : unsigned char {
|
|
Default,
|
|
|
|
/// Inherently fragile language structures are not only resilient,
|
|
/// but they have never been exposed as resilient. This permits
|
|
/// certain kinds of optimizations that are not otherwise possible
|
|
/// because of the need for backward compatibility.
|
|
InherentlyFragile,
|
|
|
|
/// Fragile language structures are non-resilient. They may have
|
|
/// been resilient at some point in the past, however.
|
|
Fragile,
|
|
|
|
/// Everything else is resilient. Resilience means different things
|
|
/// on different kinds of objects.
|
|
Resilient
|
|
};
|
|
|
|
|
|
enum class AbstractCC : unsigned char;
|
|
|
|
// Define enumerators for each attribute, e.g. AK_weak.
|
|
enum AttrKind {
|
|
#define ATTR(X) AK_##X,
|
|
#include "swift/AST/Attr.def"
|
|
AK_Count
|
|
};
|
|
|
|
// Define enumerators for each type attribute, e.g. TAK_weak.
|
|
enum TypeAttrKind {
|
|
#define ATTR(X)
|
|
#define TYPE_ATTR(X) TAK_##X,
|
|
#include "swift/AST/Attr.def"
|
|
TAK_Count
|
|
};
|
|
|
|
|
|
|
|
/// TypeAttributes - These are attributes that may be applied to types.
|
|
class TypeAttributes {
|
|
// 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[TAK_Count];
|
|
public:
|
|
/// 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.
|
|
SourceLoc AtLoc;
|
|
Optional<AbstractCC> cc = Nothing;
|
|
|
|
TypeAttributes() {}
|
|
|
|
bool isValid() const { return AtLoc.isValid(); }
|
|
|
|
void clearAttribute(TypeAttrKind A) {
|
|
AttrLocs[A] = SourceLoc();
|
|
}
|
|
|
|
bool has(TypeAttrKind A) const {
|
|
return getLoc(A).isValid();
|
|
}
|
|
|
|
SourceLoc getLoc(TypeAttrKind A) const {
|
|
return AttrLocs[A];
|
|
}
|
|
|
|
void setAttr(TypeAttrKind A, SourceLoc L) {
|
|
assert(!L.isInvalid() && "Cannot clear attribute with this method");
|
|
AttrLocs[A] = L;
|
|
}
|
|
|
|
// 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 (SourceLoc elt : AttrLocs)
|
|
if (elt.isValid()) return false;
|
|
return true;
|
|
}
|
|
|
|
bool hasCC() const { return cc.hasValue(); }
|
|
AbstractCC getAbstractCC() const { return *cc; }
|
|
|
|
bool hasOwnership() const { return getOwnership() != Ownership::Strong; }
|
|
Ownership getOwnership() const {
|
|
if (has(TAK_sil_weak)) return Ownership::Weak;
|
|
if (has(TAK_sil_unowned)) return Ownership::Unowned;
|
|
return Ownership::Strong;
|
|
}
|
|
|
|
void clearOwnership() {
|
|
clearAttribute(TAK_sil_weak);
|
|
clearAttribute(TAK_sil_unowned);
|
|
}
|
|
};
|
|
|
|
|
|
/// DeclAttributes - These are attributes that may be applied to declarations.
|
|
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:
|
|
/// 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.
|
|
SourceLoc AtLoc;
|
|
StringRef AsmName;
|
|
|
|
DeclAttributes() {}
|
|
|
|
bool isValid() const { return AtLoc.isValid(); }
|
|
|
|
void clearAttribute(AttrKind A) {
|
|
AttrLocs[A] = SourceLoc();
|
|
HasAttr[A] = false;
|
|
}
|
|
|
|
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 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 isIBOutlet() const { return has(AK_iboutlet); }
|
|
bool isIBAction() const { return has(AK_ibaction); }
|
|
bool isClassProtocol() const { return has(AK_class_protocol); }
|
|
bool isWeak() const { return has(AK_weak); }
|
|
bool isUnowned() const { return has(AK_unowned); }
|
|
bool isExported() const { return has(AK_exported); }
|
|
bool isOptional() const { return has(AK_optional); }
|
|
|
|
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;
|
|
}
|
|
|
|
void clearOwnership() {
|
|
clearAttribute(AK_weak);
|
|
clearAttribute(AK_unowned);
|
|
}
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|