Add AttrId to Attribute_
This commit is contained in:
parent
6304a27b80
commit
c305473d3c
@ -91,7 +91,12 @@ pub fn calculate(krate: &ast::Crate) -> Svh {
|
||||
// types and then use hash_content. But, since all crate
|
||||
// attributes should appear near beginning of the file, it is
|
||||
// not such a big deal to be sensitive to their spans for now.
|
||||
krate.attrs.hash(&mut state);
|
||||
//
|
||||
// We hash only the MetaItems instead of the entire Attribute
|
||||
// to avoid hashing the AttrId
|
||||
for attr in krate.attrs.iter() {
|
||||
attr.node.value.hash(&mut state);
|
||||
}
|
||||
|
||||
let hash = state.result();
|
||||
return Svh {
|
||||
|
@ -78,7 +78,7 @@ fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
with_version("std"),
|
||||
ast::DUMMY_NODE_ID),
|
||||
attrs: vec!(
|
||||
attr::mk_attr_outer(attr::mk_list_item(
|
||||
attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
|
||||
InternedString::new("phase"),
|
||||
vec!(
|
||||
attr::mk_word_item(InternedString::new("syntax")),
|
||||
@ -110,7 +110,8 @@ fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
// Add it during the prelude injection instead.
|
||||
|
||||
// Add #![feature(phase)] here, because we use #[phase] on extern crate std.
|
||||
let feat_phase_attr = attr::mk_attr_inner(attr::mk_list_item(
|
||||
let feat_phase_attr = attr::mk_attr_inner(attr::mk_attr_id(),
|
||||
attr::mk_list_item(
|
||||
InternedString::new("feature"),
|
||||
vec![attr::mk_word_item(InternedString::new("phase"))],
|
||||
));
|
||||
@ -138,7 +139,8 @@ fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
// This must happen here and not in StandardLibraryInjector because this
|
||||
// fold happens second.
|
||||
|
||||
let no_std_attr = attr::mk_attr_inner(attr::mk_word_item(InternedString::new("no_std")));
|
||||
let no_std_attr = attr::mk_attr_inner(attr::mk_attr_id(),
|
||||
attr::mk_word_item(InternedString::new("no_std")));
|
||||
krate.attrs.push(no_std_attr);
|
||||
|
||||
if !no_prelude(krate.attrs.as_slice()) {
|
||||
@ -146,7 +148,8 @@ fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
// `#![no_implicit_prelude]` at the crate level.
|
||||
|
||||
// fold_mod() will insert glob path.
|
||||
let globs_attr = attr::mk_attr_inner(attr::mk_list_item(
|
||||
let globs_attr = attr::mk_attr_inner(attr::mk_attr_id(),
|
||||
attr::mk_list_item(
|
||||
InternedString::new("feature"),
|
||||
vec!(
|
||||
attr::mk_word_item(InternedString::new("globs")),
|
||||
|
@ -341,7 +341,8 @@ pub fn main() {
|
||||
// This attribute tells resolve to let us call unexported functions
|
||||
let resolve_unexported_str = InternedString::new("!resolve_unexported");
|
||||
let resolve_unexported_attr =
|
||||
attr::mk_attr_inner(attr::mk_word_item(resolve_unexported_str));
|
||||
attr::mk_attr_inner(attr::mk_attr_id(),
|
||||
attr::mk_word_item(resolve_unexported_str));
|
||||
|
||||
let item = ast::Item {
|
||||
ident: token::str_to_ident("__test"),
|
||||
|
@ -1056,6 +1056,7 @@ fn get_attributes(md: ebml::Doc) -> Vec<ast::Attribute> {
|
||||
attrs.push(
|
||||
codemap::Spanned {
|
||||
node: ast::Attribute_ {
|
||||
id: attr::mk_attr_id(),
|
||||
style: ast::AttrOuter,
|
||||
value: meta_item,
|
||||
is_sugared_doc: false,
|
||||
|
@ -1436,7 +1436,7 @@ fn synthesize_crate_attrs(ecx: &EncodeContext,
|
||||
fn synthesize_crateid_attr(ecx: &EncodeContext) -> Attribute {
|
||||
assert!(!ecx.link_meta.crateid.name.is_empty());
|
||||
|
||||
attr::mk_attr_inner(
|
||||
attr::mk_attr_inner(attr::mk_attr_id(),
|
||||
attr::mk_name_value_item_str(
|
||||
InternedString::new("crate_id"),
|
||||
token::intern_and_get_ident(ecx.link_meta
|
||||
|
@ -228,8 +228,9 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
|
||||
let f = decl_rust_fn(ccx, fn_ty, name);
|
||||
|
||||
csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| {
|
||||
set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr_outer(x))
|
||||
.collect::<Vec<_>>().as_slice(), f)
|
||||
set_llvm_fn_attrs(meta_items.iter().map(|&x| {
|
||||
attr::mk_attr_outer(attr::mk_attr_id(), x)
|
||||
}).collect::<Vec<_>>().as_slice(), f)
|
||||
});
|
||||
|
||||
ccx.externs.borrow_mut().insert(name.to_strbuf(), f);
|
||||
|
@ -1024,9 +1024,13 @@ pub enum AttrStyle {
|
||||
AttrInner,
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
|
||||
pub struct AttrId(pub uint);
|
||||
|
||||
// doc-comments are promoted to attributes that have is_sugared_doc = true
|
||||
#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
|
||||
pub struct Attribute_ {
|
||||
pub id: AttrId,
|
||||
pub style: AttrStyle,
|
||||
pub value: @MetaItem,
|
||||
pub is_sugared_doc: bool,
|
||||
|
@ -11,7 +11,7 @@
|
||||
// Functions dealing with attributes and meta items
|
||||
|
||||
use ast;
|
||||
use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
|
||||
use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
|
||||
use codemap::{Span, Spanned, spanned, dummy_spanned};
|
||||
use codemap::BytePos;
|
||||
use diagnostic::SpanHandler;
|
||||
@ -22,6 +22,18 @@
|
||||
|
||||
use collections::HashSet;
|
||||
|
||||
local_data_key!(used_attrs: HashSet<AttrId>)
|
||||
|
||||
pub fn mark_used(attr: &Attribute) {
|
||||
let mut used = used_attrs.replace(None).unwrap_or_else(|| HashSet::new());
|
||||
used.insert(attr.node.id);
|
||||
used_attrs.replace(Some(used));
|
||||
}
|
||||
|
||||
pub fn is_used(attr: &Attribute) -> bool {
|
||||
used_attrs.get().map_or(false, |used| used.contains(&attr.node.id))
|
||||
}
|
||||
|
||||
pub trait AttrMetaMethods {
|
||||
// This could be changed to `fn check_name(&self, name: InternedString) ->
|
||||
// bool` which would facilitate a side table recording which
|
||||
@ -127,9 +139,9 @@ fn desugar_doc(&self) -> Attribute {
|
||||
token::intern_and_get_ident(strip_doc_comment_decoration(
|
||||
comment.get()).as_slice()));
|
||||
if self.node.style == ast::AttrOuter {
|
||||
mk_attr_outer(meta)
|
||||
mk_attr_outer(self.node.id, meta)
|
||||
} else {
|
||||
mk_attr_inner(meta)
|
||||
mk_attr_inner(self.node.id, meta)
|
||||
}
|
||||
} else {
|
||||
*self
|
||||
@ -158,9 +170,18 @@ pub fn mk_word_item(name: InternedString) -> @MetaItem {
|
||||
@dummy_spanned(MetaWord(name))
|
||||
}
|
||||
|
||||
local_data_key!(next_attr_id: uint)
|
||||
|
||||
pub fn mk_attr_id() -> AttrId {
|
||||
let id = next_attr_id.replace(None).unwrap_or(0);
|
||||
next_attr_id.replace(Some(id + 1));
|
||||
AttrId(id)
|
||||
}
|
||||
|
||||
/// Returns an inner attribute with the given value.
|
||||
pub fn mk_attr_inner(item: @MetaItem) -> Attribute {
|
||||
pub fn mk_attr_inner(id: AttrId, item: @MetaItem) -> Attribute {
|
||||
dummy_spanned(Attribute_ {
|
||||
id: id,
|
||||
style: ast::AttrInner,
|
||||
value: item,
|
||||
is_sugared_doc: false,
|
||||
@ -168,19 +189,22 @@ pub fn mk_attr_inner(item: @MetaItem) -> Attribute {
|
||||
}
|
||||
|
||||
/// Returns an outer attribute with the given value.
|
||||
pub fn mk_attr_outer(item: @MetaItem) -> Attribute {
|
||||
pub fn mk_attr_outer(id: AttrId, item: @MetaItem) -> Attribute {
|
||||
dummy_spanned(Attribute_ {
|
||||
id: id,
|
||||
style: ast::AttrOuter,
|
||||
value: item,
|
||||
is_sugared_doc: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn mk_sugared_doc_attr(text: InternedString, lo: BytePos, hi: BytePos)
|
||||
pub fn mk_sugared_doc_attr(id: AttrId, text: InternedString, lo: BytePos,
|
||||
hi: BytePos)
|
||||
-> Attribute {
|
||||
let style = doc_comment_style(text.get());
|
||||
let lit = spanned(lo, hi, ast::LitStr(text, ast::CookedStr));
|
||||
let attr = Attribute_ {
|
||||
id: id,
|
||||
style: style,
|
||||
value: @spanned(lo, hi, MetaNameValue(InternedString::new("doc"),
|
||||
lit)),
|
||||
|
@ -231,7 +231,7 @@ fn item_ty_poly(&self,
|
||||
generics: Generics) -> @ast::Item;
|
||||
fn item_ty(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> @ast::Item;
|
||||
|
||||
fn attribute(&self, sp: Span, mi: @ast::MetaItem) -> ast::Attribute;
|
||||
fn attribute(&self, id: AttrId, sp: Span, mi: @ast::MetaItem) -> ast::Attribute;
|
||||
|
||||
fn meta_word(&self, sp: Span, w: InternedString) -> @ast::MetaItem;
|
||||
fn meta_list(&self,
|
||||
@ -925,8 +925,10 @@ fn item_ty(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> @ast::Item {
|
||||
self.item_ty_poly(span, name, ty, ast_util::empty_generics())
|
||||
}
|
||||
|
||||
fn attribute(&self, sp: Span, mi: @ast::MetaItem) -> ast::Attribute {
|
||||
fn attribute(&self, id: ast::AttrId, sp: Span, mi: @ast::MetaItem)
|
||||
-> ast::Attribute {
|
||||
respan(sp, ast::Attribute_ {
|
||||
id: id,
|
||||
style: ast::AttrOuter,
|
||||
value: mi,
|
||||
is_sugared_doc: false,
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use attr;
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
@ -21,7 +22,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
|
||||
item: @Item,
|
||||
push: |@Item|) {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
let trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -34,7 +35,7 @@ fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
|
||||
macro_rules! md (
|
||||
($name:expr, $f:ident) => { {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
MethodDef {
|
||||
name: $name,
|
||||
generics: LifetimeBounds::empty(),
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use ast;
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -24,7 +25,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
|
||||
macro_rules! md (
|
||||
($name:expr, $op:expr, $equal:expr) => { {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
MethodDef {
|
||||
name: $name,
|
||||
generics: LifetimeBounds::empty(),
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -37,8 +38,8 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> @E
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let hidden = cx.meta_word(span, InternedString::new("hidden"));
|
||||
let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden));
|
||||
let attrs = vec!(cx.attribute(span, inline),
|
||||
cx.attribute(span, doc));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline),
|
||||
cx.attribute(attr::mk_attr_id(), span, doc));
|
||||
let trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use ast;
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -24,7 +25,7 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
|
||||
item: @Item,
|
||||
push: |@Item|) {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
let trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -21,7 +22,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
|
||||
item: @Item,
|
||||
push: |@Item|) {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
let trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -182,6 +182,7 @@ fn eq(&self, other: &int) -> bool {
|
||||
use ast;
|
||||
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
|
||||
use ast_util;
|
||||
use attr;
|
||||
use attr::AttrMetaMethods;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -427,6 +428,7 @@ fn create_derived_impl(&self,
|
||||
self_ty_params.into_vec()), None);
|
||||
|
||||
let attr = cx.attribute(
|
||||
attr::mk_attr_id(),
|
||||
self.span,
|
||||
cx.meta_word(self.span,
|
||||
InternedString::new("automatically_derived")));
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use ast;
|
||||
use ast::{MetaItem, Item, Expr, MutMutable};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -37,7 +38,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
|
||||
Path::new(vec!("std", "hash", "sip", "SipState")))
|
||||
};
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
let hash_trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use ast;
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -22,7 +23,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
|
||||
item: @Item,
|
||||
push: |@Item|) {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
let trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{MetaItem, Item, Expr};
|
||||
use attr;
|
||||
use codemap::Span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
@ -21,7 +22,7 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
|
||||
item: @Item,
|
||||
push: |@Item|) {
|
||||
let inline = cx.meta_word(span, InternedString::new("inline"));
|
||||
let attrs = vec!(cx.attribute(span, inline));
|
||||
let attrs = vec!(cx.attribute(attr::mk_attr_id(), span, inline));
|
||||
let trait_def = TraitDef {
|
||||
span: span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -972,6 +972,7 @@ mod test {
|
||||
use super::*;
|
||||
use ast;
|
||||
use ast::{Attribute_, AttrOuter, MetaWord};
|
||||
use attr;
|
||||
use codemap;
|
||||
use codemap::Spanned;
|
||||
use ext::base::{CrateLoader, MacroCrate};
|
||||
@ -1103,6 +1104,7 @@ fn make_dummy_attr(s: &str) -> ast::Attribute {
|
||||
Spanned {
|
||||
span:codemap::DUMMY_SP,
|
||||
node: Attribute_ {
|
||||
id: attr::mk_attr_id(),
|
||||
style: AttrOuter,
|
||||
value: @Spanned {
|
||||
node: MetaWord(token::intern_and_get_ident(s)),
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use ast;
|
||||
use ast::P;
|
||||
use attr;
|
||||
use codemap::{Span, respan};
|
||||
use ext::base::*;
|
||||
use ext::base;
|
||||
@ -382,7 +383,8 @@ fn static_attrs(&self) -> Vec<ast::Attribute> {
|
||||
.meta_word(self.fmtsp,
|
||||
InternedString::new(
|
||||
"address_insignificant"));
|
||||
let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
|
||||
let unnamed = self.ecx.attribute(attr::mk_attr_id(), self.fmtsp,
|
||||
unnamed);
|
||||
|
||||
// Do not warn format string as dead code
|
||||
let dead_code = self.ecx.meta_word(self.fmtsp,
|
||||
@ -390,7 +392,8 @@ fn static_attrs(&self) -> Vec<ast::Attribute> {
|
||||
let allow_dead_code = self.ecx.meta_list(self.fmtsp,
|
||||
InternedString::new("allow"),
|
||||
vec!(dead_code));
|
||||
let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
|
||||
let allow_dead_code = self.ecx.attribute(attr::mk_attr_id(), self.fmtsp,
|
||||
allow_dead_code);
|
||||
return vec!(unnamed, allow_dead_code);
|
||||
}
|
||||
|
||||
|
@ -360,6 +360,7 @@ fn fold_attribute_<T: Folder>(at: Attribute, fld: &mut T) -> Attribute {
|
||||
Spanned {
|
||||
span: fld.new_span(at.span),
|
||||
node: ast::Attribute_ {
|
||||
id: at.node.id,
|
||||
style: at.node.style,
|
||||
value: fold_meta_item_(at.node.value, fld),
|
||||
is_sugared_doc: at.node.is_sugared_doc
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use attr;
|
||||
use ast;
|
||||
use codemap::{spanned, Spanned, mk_sp, Span};
|
||||
use parse::common::*; //resolve bug?
|
||||
@ -39,6 +40,7 @@ fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
|
||||
}
|
||||
token::DOC_COMMENT(s) => {
|
||||
let attr = ::attr::mk_sugared_doc_attr(
|
||||
attr::mk_attr_id(),
|
||||
self.id_to_interned_str(s),
|
||||
self.span.lo,
|
||||
self.span.hi
|
||||
@ -101,6 +103,7 @@ fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
|
||||
return Spanned {
|
||||
span: span,
|
||||
node: ast::Attribute_ {
|
||||
id: attr::mk_attr_id(),
|
||||
style: style,
|
||||
value: value,
|
||||
is_sugared_doc: false
|
||||
@ -132,7 +135,10 @@ fn parse_inner_attrs_and_next(&mut self)
|
||||
// we need to get the position of this token before we bump.
|
||||
let Span { lo, hi, .. } = self.span;
|
||||
self.bump();
|
||||
::attr::mk_sugared_doc_attr(self.id_to_interned_str(s), lo, hi)
|
||||
::attr::mk_sugared_doc_attr(attr::mk_attr_id(),
|
||||
self.id_to_interned_str(s),
|
||||
lo,
|
||||
hi)
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user