diff --git a/src/doc/grammar.md b/src/doc/grammar.md index ee9135b6578f6..4501d74073e90 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -1,812 +1,7 @@ % Grammar -# Introduction +The Rust grammar may now be found in the [reference]. Additionally, the [grammar +working group] is working on producing a testable grammar. -This document is the primary reference for the Rust programming language grammar. It -provides only one kind of material: - - - Chapters that formally define the language grammar. - -This document does not serve as an introduction to the language. Background -familiarity with the language is assumed. A separate [guide] is available to -help acquire such background. - -This document also does not serve as a reference to the [standard] library -included in the language distribution. Those libraries are documented -separately by extracting documentation attributes from their source code. Many -of the features that one might expect to be language features are library -features in Rust, so what you're looking for may be there, not here. - -[guide]: guide.html -[standard]: std/index.html - -# Notation - -Rust's grammar is defined over Unicode codepoints, each conventionally denoted -`U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's grammar is -confined to the ASCII range of Unicode, and is described in this document by a -dialect of Extended Backus-Naur Form (EBNF), specifically a dialect of EBNF -supported by common automated LL(k) parsing tools such as `llgen`, rather than -the dialect given in ISO 14977. The dialect can be defined self-referentially -as follows: - -```antlr -grammar : rule + ; -rule : nonterminal ':' productionrule ';' ; -productionrule : production [ '|' production ] * ; -production : term * ; -term : element repeats ; -element : LITERAL | IDENTIFIER | '[' productionrule ']' ; -repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ; -``` - -Where: - -- Whitespace in the grammar is ignored. -- Square brackets are used to group rules. -- `LITERAL` is a single printable ASCII character, or an escaped hexadecimal - ASCII code of the form `\xQQ`, in single quotes, denoting the corresponding - Unicode codepoint `U+00QQ`. -- `IDENTIFIER` is a nonempty string of ASCII letters and underscores. -- The `repeat` forms apply to the adjacent `element`, and are as follows: - - `?` means zero or one repetition - - `*` means zero or more repetitions - - `+` means one or more repetitions - - NUMBER trailing a repeat symbol gives a maximum repetition count - - NUMBER on its own gives an exact repetition count - -This EBNF dialect should hopefully be familiar to many readers. - -## Unicode productions - -A few productions in Rust's grammar permit Unicode codepoints outside the ASCII -range. We define these productions in terms of character properties specified -in the Unicode standard, rather than in terms of ASCII-range codepoints. The -section [Special Unicode Productions](#special-unicode-productions) lists these -productions. - -## String table productions - -Some rules in the grammar — notably [unary -operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), and [keywords](#keywords) — are -given in a simplified form: as a listing of a table of unquoted, printable -whitespace-separated strings. These cases form a subset of the rules regarding -the [token](#tokens) rule, and are assumed to be the result of a -lexical-analysis phase feeding the parser, driven by a DFA, operating over the -disjunction of all such string table entries. - -When such a string enclosed in double-quotes (`"`) occurs inside the grammar, -it is an implicit reference to a single member of such a string table -production. See [tokens](#tokens) for more information. - -# Lexical structure - -## Input format - -Rust input is interpreted as a sequence of Unicode codepoints encoded in UTF-8. -Most Rust grammar rules are defined in terms of printable ASCII-range -codepoints, but a small number are defined in terms of Unicode properties or -explicit codepoint lists. [^inputformat] - -[^inputformat]: Substitute definitions for the special Unicode productions are - provided to the grammar verifier, restricted to ASCII range, when verifying the - grammar in this document. - -## Special Unicode Productions - -The following productions in the Rust grammar are defined in terms of Unicode -properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and -`non_double_quote`. - -### Identifiers - -The `ident` production is any nonempty Unicode string of -the following form: - -- The first character is in one of the following ranges `U+0041` to `U+005A` -("A" to "Z"), `U+0061` to `U+007A` ("a" to "z"), or `U+005F` ("\_"). -- The remaining characters are in the range `U+0030` to `U+0039` ("0" to "9"), -or any of the prior valid initial characters. - -as long as the identifier does _not_ occur in the set of [keywords](#keywords). - -### Delimiter-restricted productions - -Some productions are defined by exclusion of particular Unicode characters: - -- `non_null` is any single Unicode character aside from `U+0000` (null) -- `non_eol` is any single Unicode character aside from `U+000A` (`'\n'`) -- `non_single_quote` is any single Unicode character aside from `U+0027` (`'`) -- `non_double_quote` is any single Unicode character aside from `U+0022` (`"`) - -## Comments - -```antlr -comment : block_comment | line_comment ; -block_comment : "/*" block_comment_body * "*/" ; -block_comment_body : [block_comment | character] * ; -line_comment : "//" non_eol * ; -``` - -**FIXME:** add doc grammar? - -## Whitespace - -```antlr -whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ; -whitespace : [ whitespace_char | comment ] + ; -``` - -## Tokens - -```antlr -simple_token : keyword | unop | binop ; -token : simple_token | ident | literal | symbol | whitespace token ; -``` - -### Keywords - -<p id="keyword-table-marker"></p> - -| | | | | | -|----------|----------|----------|----------|----------| -| _ | abstract | alignof | as | become | -| box | break | const | continue | crate | -| do | else | enum | extern | false | -| final | fn | for | if | impl | -| in | let | loop | macro | match | -| mod | move | mut | offsetof | override | -| priv | proc | pub | pure | ref | -| return | Self | self | sizeof | static | -| struct | super | trait | true | type | -| typeof | unsafe | unsized | use | virtual | -| where | while | yield | | | - - -Each of these keywords has special meaning in its grammar, and all of them are -excluded from the `ident` rule. - -Not all of these keywords are used by the language. Some of them were used -before Rust 1.0, and were left reserved once their implementations were -removed. Some of them were reserved before 1.0 to make space for possible -future features. - -### Literals - -```antlr -lit_suffix : ident; -literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit | bool_lit ] lit_suffix ?; -``` - -The optional `lit_suffix` production is only used for certain numeric literals, -but is reserved for future extension. That is, the above gives the lexical -grammar, but a Rust parser will reject everything but the 12 special cases -mentioned in [Number literals](reference/tokens.html#number-literals) in the -reference. - -#### Character and string literals - -```antlr -char_lit : '\x27' char_body '\x27' ; -string_lit : '"' string_body * '"' | 'r' raw_string ; - -char_body : non_single_quote - | '\x5c' [ '\x27' | common_escape | unicode_escape ] ; - -string_body : non_double_quote - | '\x5c' [ '\x22' | common_escape | unicode_escape ] ; -raw_string : '"' raw_string_body '"' | '#' raw_string '#' ; - -common_escape : '\x5c' - | 'n' | 'r' | 't' | '0' - | 'x' hex_digit 2 -unicode_escape : 'u' '{' hex_digit+ 6 '}'; - -hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f' - | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' - | dec_digit ; -oct_digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ; -dec_digit : '0' | nonzero_dec ; -nonzero_dec: '1' | '2' | '3' | '4' - | '5' | '6' | '7' | '8' | '9' ; -``` - -#### Byte and byte string literals - -```antlr -byte_lit : "b\x27" byte_body '\x27' ; -byte_string_lit : "b\x22" string_body * '\x22' | "br" raw_byte_string ; - -byte_body : ascii_non_single_quote - | '\x5c' [ '\x27' | common_escape ] ; - -byte_string_body : ascii_non_double_quote - | '\x5c' [ '\x22' | common_escape ] ; -raw_byte_string : '"' raw_byte_string_body '"' | '#' raw_byte_string '#' ; - -``` - -#### Number literals - -```antlr -num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ? - | '0' [ [ dec_digit | '_' ] * float_suffix ? - | 'b' [ '1' | '0' | '_' ] + - | 'o' [ oct_digit | '_' ] + - | 'x' [ hex_digit | '_' ] + ] ; - -float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ; - -exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ; -dec_lit : [ dec_digit | '_' ] + ; -``` - -#### Boolean literals - -```antlr -bool_lit : [ "true" | "false" ] ; -``` - -The two values of the boolean type are written `true` and `false`. - -### Symbols - -```antlr -symbol : "::" | "->" - | '#' | '[' | ']' | '(' | ')' | '{' | '}' - | ',' | ';' ; -``` - -Symbols are a general class of printable [tokens](#tokens) that play structural -roles in a variety of grammar productions. They are cataloged here for -completeness as the set of remaining miscellaneous printable tokens that do not -otherwise appear as [unary operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), or [keywords](#keywords). - -## Paths - -```antlr -expr_path : [ "::" ] ident [ "::" expr_path_tail ] + ; -expr_path_tail : '<' type_expr [ ',' type_expr ] + '>' - | expr_path ; - -type_path : ident [ type_path_tail ] + ; -type_path_tail : '<' type_expr [ ',' type_expr ] + '>' - | "::" type_path ; -``` - -# Syntax extensions - -## Macros - -```antlr -expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ';' - | "macro_rules" '!' ident '{' macro_rule * '}' ; -macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ; -matcher : '(' matcher * ')' | '[' matcher * ']' - | '{' matcher * '}' | '$' ident ':' ident - | '$' '(' matcher * ')' sep_token? [ '*' | '+' ] - | non_special_token ; -transcriber : '(' transcriber * ')' | '[' transcriber * ']' - | '{' transcriber * '}' | '$' ident - | '$' '(' transcriber * ')' sep_token? [ '*' | '+' ] - | non_special_token ; -``` - -# Crates and source files - -**FIXME:** grammar? What production covers #![crate_id = "foo"] ? - -# Items and attributes - -**FIXME:** grammar? - -## Items - -```antlr -item : vis ? mod_item | fn_item | type_item | struct_item | enum_item - | const_item | static_item | trait_item | impl_item | extern_block_item ; -``` - -### Type Parameters - -**FIXME:** grammar? - -### Modules - -```antlr -mod_item : "mod" ident ( ';' | '{' mod '}' ); -mod : [ view_item | item ] * ; -``` - -#### View items - -```antlr -view_item : extern_crate_decl | use_decl ';' ; -``` - -##### Extern crate declarations - -```antlr -extern_crate_decl : "extern" "crate" crate_name -crate_name: ident | ( ident "as" ident ) -``` - -##### Use declarations - -```antlr -use_decl : vis ? "use" [ path "as" ident - | path_glob ] ; - -path_glob : ident [ "::" [ path_glob - | '*' ] ] ? - | '{' path_item [ ',' path_item ] * '}' ; - -path_item : ident | "self" ; -``` - -### Functions - -**FIXME:** grammar? - -#### Generic functions - -**FIXME:** grammar? - -#### Unsafety - -**FIXME:** grammar? - -##### Unsafe functions - -**FIXME:** grammar? - -##### Unsafe blocks - -**FIXME:** grammar? - -#### Diverging functions - -**FIXME:** grammar? - -### Type definitions - -**FIXME:** grammar? - -### Structures - -**FIXME:** grammar? - -### Enumerations - -**FIXME:** grammar? - -### Constant items - -```antlr -const_item : "const" ident ':' type '=' expr ';' ; -``` - -### Static items - -```antlr -static_item : "static" ident ':' type '=' expr ';' ; -``` - -#### Mutable statics - -**FIXME:** grammar? - -### Traits - -**FIXME:** grammar? - -### Implementations - -**FIXME:** grammar? - -### External blocks - -```antlr -extern_block_item : "extern" '{' extern_block '}' ; -extern_block : [ foreign_fn ] * ; -``` - -## Visibility and Privacy - -```antlr -vis : "pub" ; -``` -### Re-exporting and Visibility - -See [Use declarations](#use-declarations). - -## Attributes - -```antlr -attribute : '#' '!' ? '[' meta_item ']' ; -meta_item : ident [ '=' literal - | '(' meta_seq ')' ] ? ; -meta_seq : meta_item [ ',' meta_seq ] ? ; -``` - -# Statements and expressions - -## Statements - -```antlr -stmt : decl_stmt | expr_stmt | ';' ; -``` - -### Declaration statements - -```antlr -decl_stmt : item | let_decl ; -``` - -#### Item declarations - -See [Items](#items). - -#### Variable declarations - -```antlr -let_decl : "let" pat [':' type ] ? [ init ] ? ';' ; -init : [ '=' ] expr ; -``` - -### Expression statements - -```antlr -expr_stmt : expr ';' ; -``` - -## Expressions - -```antlr -expr : literal | path | tuple_expr | unit_expr | struct_expr - | block_expr | method_call_expr | field_expr | array_expr - | idx_expr | range_expr | unop_expr | binop_expr - | paren_expr | call_expr | lambda_expr | while_expr - | loop_expr | break_expr | continue_expr | for_expr - | if_expr | match_expr | if_let_expr | while_let_expr - | return_expr ; -``` - -#### Lvalues, rvalues and temporaries - -**FIXME:** grammar? - -#### Moved and copied types - -**FIXME:** Do we want to capture this in the grammar as different productions? - -### Literal expressions - -See [Literals](#literals). - -### Path expressions - -See [Paths](#paths). - -### Tuple expressions - -```antlr -tuple_expr : '(' [ expr [ ',' expr ] * | expr ',' ] ? ')' ; -``` - -### Unit expressions - -```antlr -unit_expr : "()" ; -``` - -### Structure expressions - -```antlr -struct_expr_field_init : ident | ident ':' expr ; -struct_expr : expr_path '{' struct_expr_field_init - [ ',' struct_expr_field_init ] * - [ ".." expr ] '}' | - expr_path '(' expr - [ ',' expr ] * ')' | - expr_path ; -``` - -### Block expressions - -```antlr -block_expr : '{' [ stmt | item ] * - [ expr ] '}' ; -``` - -### Method-call expressions - -```antlr -method_call_expr : expr '.' ident paren_expr_list ; -``` - -### Field expressions - -```antlr -field_expr : expr '.' ident ; -``` - -### Array expressions - -```antlr -array_expr : '[' "mut" ? array_elems? ']' ; - -array_elems : [expr [',' expr]*] | [expr ';' expr] ; -``` - -### Index expressions - -```antlr -idx_expr : expr '[' expr ']' ; -``` - -### Range expressions - -```antlr -range_expr : expr ".." expr | - expr ".." | - ".." expr | - ".." ; -``` - -### Unary operator expressions - -```antlr -unop_expr : unop expr ; -unop : '-' | '*' | '!' ; -``` - -### Binary operator expressions - -```antlr -binop_expr : expr binop expr | type_cast_expr - | assignment_expr | compound_assignment_expr ; -binop : arith_op | bitwise_op | lazy_bool_op | comp_op -``` - -#### Arithmetic operators - -```antlr -arith_op : '+' | '-' | '*' | '/' | '%' ; -``` - -#### Bitwise operators - -```antlr -bitwise_op : '&' | '|' | '^' | "<<" | ">>" ; -``` - -#### Lazy boolean operators - -```antlr -lazy_bool_op : "&&" | "||" ; -``` - -#### Comparison operators - -```antlr -comp_op : "==" | "!=" | '<' | '>' | "<=" | ">=" ; -``` - -#### Type cast expressions - -```antlr -type_cast_expr : value "as" type ; -``` - -#### Assignment expressions - -```antlr -assignment_expr : expr '=' expr ; -``` - -#### Compound assignment expressions - -```antlr -compound_assignment_expr : expr [ arith_op | bitwise_op ] '=' expr ; -``` - -### Grouped expressions - -```antlr -paren_expr : '(' expr ')' ; -``` - -### Call expressions - -```antlr -expr_list : [ expr [ ',' expr ]* ] ? ; -paren_expr_list : '(' expr_list ')' ; -call_expr : expr paren_expr_list ; -``` - -### Lambda expressions - -```antlr -ident_list : [ ident [ ',' ident ]* ] ? ; -lambda_expr : '|' ident_list '|' expr ; -``` - -### While loops - -```antlr -while_expr : [ lifetime ':' ] ? "while" no_struct_literal_expr '{' block '}' ; -``` - -### Infinite loops - -```antlr -loop_expr : [ lifetime ':' ] ? "loop" '{' block '}'; -``` - -### Break expressions - -```antlr -break_expr : "break" [ lifetime ] ?; -``` - -### Continue expressions - -```antlr -continue_expr : "continue" [ lifetime ] ?; -``` - -### For expressions - -```antlr -for_expr : [ lifetime ':' ] ? "for" pat "in" no_struct_literal_expr '{' block '}' ; -``` - -### If expressions - -```antlr -if_expr : "if" no_struct_literal_expr '{' block '}' - else_tail ? ; - -else_tail : "else" [ if_expr | if_let_expr - | '{' block '}' ] ; -``` - -### Match expressions - -```antlr -match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ; - -match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ; - -match_pat : pat [ '|' pat ] * [ "if" expr ] ? ; -``` - -### If let expressions - -```antlr -if_let_expr : "if" "let" pat '=' expr '{' block '}' - else_tail ? ; -``` - -### While let loops - -```antlr -while_let_expr : [ lifetime ':' ] ? "while" "let" pat '=' expr '{' block '}' ; -``` - -### Return expressions - -```antlr -return_expr : "return" expr ? ; -``` - -# Type system - -**FIXME:** is this entire chapter relevant here? Or should it all have been covered by some production already? - -## Types - -### Primitive types - -**FIXME:** grammar? - -#### Machine types - -**FIXME:** grammar? - -#### Machine-dependent integer types - -**FIXME:** grammar? - -### Textual types - -**FIXME:** grammar? - -### Tuple types - -**FIXME:** grammar? - -### Array, and Slice types - -**FIXME:** grammar? - -### Structure types - -**FIXME:** grammar? - -### Enumerated types - -**FIXME:** grammar? - -### Pointer types - -**FIXME:** grammar? - -### Function types - -**FIXME:** grammar? - -### Closure types - -```antlr -closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|' - [ ':' bound-list ] [ '->' type ] -lifetime-list := lifetime | lifetime ',' lifetime-list -arg-list := ident ':' type | ident ':' type ',' arg-list -``` - -### Never type -An empty type - -```antlr -never_type : "!" ; -``` - -### Object types - -**FIXME:** grammar? - -### Type parameters - -**FIXME:** grammar? - -### Type parameter bounds - -```antlr -bound-list := bound | bound '+' bound-list '+' ? -bound := ty_bound | lt_bound -lt_bound := lifetime -ty_bound := ty_bound_noparen | (ty_bound_noparen) -ty_bound_noparen := [?] [ for<lt_param_defs> ] simple_path -``` - -### Self types - -**FIXME:** grammar? - -## Type kinds - -**FIXME:** this is probably not relevant to the grammar... - -# Memory and concurrency models - -**FIXME:** is this entire chapter relevant here? Or should it all have been covered by some production already? - -## Memory model - -### Memory allocation and lifetime - -### Memory ownership - -### Variables - -### Boxes - -## Threads - -### Communication between threads - -### Thread lifecycle +[reference]: https://doc.rust-lang.org/reference/ +[grammar working group]: https://github.com/rust-lang/wg-grammar diff --git a/src/grammar/.gitignore b/src/grammar/.gitignore deleted file mode 100644 index 3e4498759434f..0000000000000 --- a/src/grammar/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.class -*.java -*.tokens diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l deleted file mode 100644 index 1feb781b2b39f..0000000000000 --- a/src/grammar/lexer.l +++ /dev/null @@ -1,350 +0,0 @@ -%{ -#include <stdio.h> -#include <ctype.h> - -static int num_hashes; -static int end_hashes; -static int saw_non_hash; - -%} - -%option stack -%option yylineno - -%x str -%x rawstr -%x rawstr_esc_begin -%x rawstr_esc_body -%x rawstr_esc_end -%x byte -%x bytestr -%x rawbytestr -%x rawbytestr_nohash -%x pound -%x shebang_or_attr -%x ltorchar -%x linecomment -%x doc_line -%x blockcomment -%x doc_block -%x suffix - -ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]* - -%% - -<suffix>{ident} { BEGIN(INITIAL); } -<suffix>(.|\n) { yyless(0); BEGIN(INITIAL); } - -[ \n\t\r] { } - -\xef\xbb\xbf { - // UTF-8 byte order mark (BOM), ignore if in line 1, error otherwise - if (yyget_lineno() != 1) { - return -1; - } -} - -\/\/(\/|\!) { BEGIN(doc_line); yymore(); } -<doc_line>\n { BEGIN(INITIAL); - yyleng--; - yytext[yyleng] = 0; - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -<doc_line>[^\n]* { yymore(); } - -\/\/|\/\/\/\/ { BEGIN(linecomment); } -<linecomment>\n { BEGIN(INITIAL); } -<linecomment>[^\n]* { } - -\/\*(\*|\!)[^*] { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); } -<doc_block>\/\* { yy_push_state(doc_block); yymore(); } -<doc_block>\*\/ { - yy_pop_state(); - if (yy_top_state() == doc_block) { - yymore(); - } else { - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -} -<doc_block>(.|\n) { yymore(); } - -\/\* { yy_push_state(blockcomment); } -<blockcomment>\/\* { yy_push_state(blockcomment); } -<blockcomment>\*\/ { yy_pop_state(); } -<blockcomment>(.|\n) { } - -_ { return UNDERSCORE; } -abstract { return ABSTRACT; } -alignof { return ALIGNOF; } -as { return AS; } -become { return BECOME; } -box { return BOX; } -break { return BREAK; } -catch { return CATCH; } -const { return CONST; } -continue { return CONTINUE; } -crate { return CRATE; } -default { return DEFAULT; } -do { return DO; } -else { return ELSE; } -enum { return ENUM; } -extern { return EXTERN; } -false { return FALSE; } -final { return FINAL; } -fn { return FN; } -for { return FOR; } -if { return IF; } -impl { return IMPL; } -in { return IN; } -let { return LET; } -loop { return LOOP; } -macro { return MACRO; } -match { return MATCH; } -mod { return MOD; } -move { return MOVE; } -mut { return MUT; } -offsetof { return OFFSETOF; } -override { return OVERRIDE; } -priv { return PRIV; } -proc { return PROC; } -pure { return PURE; } -pub { return PUB; } -ref { return REF; } -return { return RETURN; } -self { return SELF; } -sizeof { return SIZEOF; } -static { return STATIC; } -struct { return STRUCT; } -super { return SUPER; } -trait { return TRAIT; } -true { return TRUE; } -type { return TYPE; } -typeof { return TYPEOF; } -union { return UNION; } -unsafe { return UNSAFE; } -unsized { return UNSIZED; } -use { return USE; } -virtual { return VIRTUAL; } -where { return WHERE; } -while { return WHILE; } -yield { return YIELD; } - -{ident} { return IDENT; } - -0x[0-9a-fA-F_]+ { BEGIN(suffix); return LIT_INTEGER; } -0o[0-7_]+ { BEGIN(suffix); return LIT_INTEGER; } -0b[01_]+ { BEGIN(suffix); return LIT_INTEGER; } -[0-9][0-9_]* { BEGIN(suffix); return LIT_INTEGER; } -[0-9][0-9_]*\.(\.|[a-zA-Z]) { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; } - -[0-9][0-9_]*\.[0-9_]*([eE][-\+]?[0-9_]+)? { BEGIN(suffix); return LIT_FLOAT; } -[0-9][0-9_]*(\.[0-9_]*)?[eE][-\+]?[0-9_]+ { BEGIN(suffix); return LIT_FLOAT; } - -; { return ';'; } -, { return ','; } -\.\.\. { return DOTDOTDOT; } -\.\. { return DOTDOT; } -\. { return '.'; } -\( { return '('; } -\) { return ')'; } -\{ { return '{'; } -\} { return '}'; } -\[ { return '['; } -\] { return ']'; } -@ { return '@'; } -# { BEGIN(pound); yymore(); } -<pound>\! { BEGIN(shebang_or_attr); yymore(); } -<shebang_or_attr>\[ { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; -} -<shebang_or_attr>[^\[\n]*\n { - // Since the \n was eaten as part of the token, yylineno will have - // been incremented to the value 2 if the shebang was on the first - // line. This yyless undoes that, setting yylineno back to 1. - yyless(yyleng - 1); - if (yyget_lineno() == 1) { - BEGIN(INITIAL); - return SHEBANG_LINE; - } else { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; - } -} -<pound>. { BEGIN(INITIAL); yyless(1); return '#'; } - -\~ { return '~'; } -:: { return MOD_SEP; } -: { return ':'; } -\$ { return '$'; } -\? { return '?'; } - -== { return EQEQ; } -=> { return FAT_ARROW; } -= { return '='; } -\!= { return NE; } -\! { return '!'; } -\<= { return LE; } -\<\< { return SHL; } -\<\<= { return SHLEQ; } -\< { return '<'; } -\>= { return GE; } -\>\> { return SHR; } -\>\>= { return SHREQ; } -\> { return '>'; } - -\x27 { BEGIN(ltorchar); yymore(); } -<ltorchar>static { BEGIN(INITIAL); return STATIC_LIFETIME; } -<ltorchar>{ident} { BEGIN(INITIAL); return LIFETIME; } -<ltorchar>\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } -<ltorchar>\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } -<ltorchar>\\u\{([0-9a-fA-F]_*){1,6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } -<ltorchar>.\x27 { BEGIN(suffix); return LIT_CHAR; } -<ltorchar>[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } -<ltorchar><<EOF>> { BEGIN(INITIAL); return -1; } - -b\x22 { BEGIN(bytestr); yymore(); } -<bytestr>\x22 { BEGIN(suffix); return LIT_BYTE_STR; } - -<bytestr><<EOF>> { return -1; } -<bytestr>\\[n\nrt\\\x27\x220] { yymore(); } -<bytestr>\\x[0-9a-fA-F]{2} { yymore(); } -<bytestr>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } -<bytestr>\\[^n\nrt\\\x27\x220] { return -1; } -<bytestr>(.|\n) { yymore(); } - -br\x22 { BEGIN(rawbytestr_nohash); yymore(); } -<rawbytestr_nohash>\x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; } -<rawbytestr_nohash>(.|\n) { yymore(); } -<rawbytestr_nohash><<EOF>> { return -1; } - -br/# { - BEGIN(rawbytestr); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} -<rawbytestr># { - if (!saw_non_hash) { - num_hashes++; - } else if (end_hashes != 0) { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - } - yymore(); -} -<rawbytestr>\x22# { - end_hashes = 1; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - yymore(); -} -<rawbytestr>(.|\n) { - if (!saw_non_hash) { - saw_non_hash = 1; - } - if (end_hashes != 0) { - end_hashes = 0; - } - yymore(); -} -<rawbytestr><<EOF>> { return -1; } - -b\x27 { BEGIN(byte); yymore(); } -<byte>\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<byte>\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<byte>\\u([0-9a-fA-F]_*){4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<byte>\\U([0-9a-fA-F]_*){8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<byte>.\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<byte><<EOF>> { BEGIN(INITIAL); return -1; } - -r\x22 { BEGIN(rawstr); yymore(); } -<rawstr>\x22 { BEGIN(suffix); return LIT_STR_RAW; } -<rawstr>(.|\n) { yymore(); } -<rawstr><<EOF>> { return -1; } - -r/# { - BEGIN(rawstr_esc_begin); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} - -<rawstr_esc_begin># { - num_hashes++; - yymore(); -} -<rawstr_esc_begin>\x22 { - BEGIN(rawstr_esc_body); - yymore(); -} -<rawstr_esc_begin>(.|\n) { return -1; } - -<rawstr_esc_body>\x22/# { - BEGIN(rawstr_esc_end); - yymore(); - } -<rawstr_esc_body>(.|\n) { - yymore(); - } - -<rawstr_esc_end># { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_STR_RAW; - } - yymore(); - } -<rawstr_esc_end>[^#] { - end_hashes = 0; - BEGIN(rawstr_esc_body); - yymore(); - } - -<rawstr_esc_begin,rawstr_esc_body,rawstr_esc_end><<EOF>> { return -1; } - -\x22 { BEGIN(str); yymore(); } -<str>\x22 { BEGIN(suffix); return LIT_STR; } - -<str><<EOF>> { return -1; } -<str>\\[n\nr\rt\\\x27\x220] { yymore(); } -<str>\\x[0-9a-fA-F]{2} { yymore(); } -<str>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); } -<str>\\[^n\nrt\\\x27\x220] { return -1; } -<str>(.|\n) { yymore(); } - -\<- { return LARROW; } --\> { return RARROW; } -- { return '-'; } --= { return MINUSEQ; } -&& { return ANDAND; } -& { return '&'; } -&= { return ANDEQ; } -\|\| { return OROR; } -\| { return '|'; } -\|= { return OREQ; } -\+ { return '+'; } -\+= { return PLUSEQ; } -\* { return '*'; } -\*= { return STAREQ; } -\/ { return '/'; } -\/= { return SLASHEQ; } -\^ { return '^'; } -\^= { return CARETEQ; } -% { return '%'; } -%= { return PERCENTEQ; } - -<<EOF>> { return 0; } - -%% diff --git a/src/grammar/parser-lalr-main.c b/src/grammar/parser-lalr-main.c deleted file mode 100644 index 6348190cc140b..0000000000000 --- a/src/grammar/parser-lalr-main.c +++ /dev/null @@ -1,193 +0,0 @@ -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -extern int yylex(); -extern int rsparse(); - -#define PUSHBACK_LEN 4 - -static char pushback[PUSHBACK_LEN]; -static int verbose; - -void print(const char* format, ...) { - va_list args; - va_start(args, format); - if (verbose) { - vprintf(format, args); - } - va_end(args); -} - -// If there is a non-null char at the head of the pushback queue, -// dequeue it and shift the rest of the queue forwards. Otherwise, -// return the token from calling yylex. -int rslex() { - if (pushback[0] == '\0') { - return yylex(); - } else { - char c = pushback[0]; - memmove(pushback, pushback + 1, PUSHBACK_LEN - 1); - pushback[PUSHBACK_LEN - 1] = '\0'; - return c; - } -} - -// Note: this does nothing if the pushback queue is full. As long as -// there aren't more than PUSHBACK_LEN consecutive calls to push_back -// in an action, this shouldn't be a problem. -void push_back(char c) { - for (int i = 0; i < PUSHBACK_LEN; ++i) { - if (pushback[i] == '\0') { - pushback[i] = c; - break; - } - } -} - -extern int rsdebug; - -struct node { - struct node *next; - struct node *prev; - int own_string; - char const *name; - int n_elems; - struct node *elems[]; -}; - -struct node *nodes = NULL; -int n_nodes; - -struct node *mk_node(char const *name, int n, ...) { - va_list ap; - int i = 0; - unsigned sz = sizeof(struct node) + (n * sizeof(struct node *)); - struct node *nn, *nd = (struct node *)malloc(sz); - - print("# New %d-ary node: %s = %p\n", n, name, nd); - - nd->own_string = 0; - nd->prev = NULL; - nd->next = nodes; - if (nodes) { - nodes->prev = nd; - } - nodes = nd; - - nd->name = name; - nd->n_elems = n; - - va_start(ap, n); - while (i < n) { - nn = va_arg(ap, struct node *); - print("# arg[%d]: %p\n", i, nn); - print("# (%s ...)\n", nn->name); - nd->elems[i++] = nn; - } - va_end(ap); - n_nodes++; - return nd; -} - -struct node *mk_atom(char *name) { - struct node *nd = mk_node((char const *)strdup(name), 0); - nd->own_string = 1; - return nd; -} - -struct node *mk_none() { - return mk_atom("<none>"); -} - -struct node *ext_node(struct node *nd, int n, ...) { - va_list ap; - int i = 0, c = nd->n_elems + n; - unsigned sz = sizeof(struct node) + (c * sizeof(struct node *)); - struct node *nn; - - print("# Extending %d-ary node by %d nodes: %s = %p", - nd->n_elems, c, nd->name, nd); - - if (nd->next) { - nd->next->prev = nd->prev; - } - if (nd->prev) { - nd->prev->next = nd->next; - } - nd = realloc(nd, sz); - nd->prev = NULL; - nd->next = nodes; - nodes->prev = nd; - nodes = nd; - - print(" ==> %p\n", nd); - - va_start(ap, n); - while (i < n) { - nn = va_arg(ap, struct node *); - print("# arg[%d]: %p\n", i, nn); - print("# (%s ...)\n", nn->name); - nd->elems[nd->n_elems++] = nn; - ++i; - } - va_end(ap); - return nd; -} - -int const indent_step = 4; - -void print_indent(int depth) { - while (depth) { - if (depth-- % indent_step == 0) { - print("|"); - } else { - print(" "); - } - } -} - -void print_node(struct node *n, int depth) { - int i = 0; - print_indent(depth); - if (n->n_elems == 0) { - print("%s\n", n->name); - } else { - print("(%s\n", n->name); - for (i = 0; i < n->n_elems; ++i) { - print_node(n->elems[i], depth + indent_step); - } - print_indent(depth); - print(")\n"); - } -} - -int main(int argc, char **argv) { - if (argc == 2 && strcmp(argv[1], "-v") == 0) { - verbose = 1; - } else { - verbose = 0; - } - int ret = 0; - struct node *tmp; - memset(pushback, '\0', PUSHBACK_LEN); - ret = rsparse(); - print("--- PARSE COMPLETE: ret:%d, n_nodes:%d ---\n", ret, n_nodes); - if (nodes) { - print_node(nodes, 0); - } - while (nodes) { - tmp = nodes; - nodes = tmp->next; - if (tmp->own_string) { - free((void*)tmp->name); - } - free(tmp); - } - return ret; -} - -void rserror(char const *s) { - fprintf(stderr, "%s\n", s); -} diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y deleted file mode 100644 index 5585c95a5a63a..0000000000000 --- a/src/grammar/parser-lalr.y +++ /dev/null @@ -1,1982 +0,0 @@ -%{ -#define YYERROR_VERBOSE -#define YYSTYPE struct node * -struct node; -extern int yylex(); -extern void yyerror(char const *s); -extern struct node *mk_node(char const *name, int n, ...); -extern struct node *mk_atom(char *text); -extern struct node *mk_none(); -extern struct node *ext_node(struct node *nd, int n, ...); -extern void push_back(char c); -extern char *yytext; -%} -%debug - -%token SHL -%token SHR -%token LE -%token EQEQ -%token NE -%token GE -%token ANDAND -%token OROR -%token SHLEQ -%token SHREQ -%token MINUSEQ -%token ANDEQ -%token OREQ -%token PLUSEQ -%token STAREQ -%token SLASHEQ -%token CARETEQ -%token PERCENTEQ -%token DOTDOT -%token DOTDOTDOT -%token MOD_SEP -%token RARROW -%token LARROW -%token FAT_ARROW -%token LIT_BYTE -%token LIT_CHAR -%token LIT_INTEGER -%token LIT_FLOAT -%token LIT_STR -%token LIT_STR_RAW -%token LIT_BYTE_STR -%token LIT_BYTE_STR_RAW -%token IDENT -%token UNDERSCORE -%token LIFETIME - -// keywords -%token SELF -%token STATIC -%token ABSTRACT -%token ALIGNOF -%token AS -%token BECOME -%token BREAK -%token CATCH -%token CRATE -%token DO -%token ELSE -%token ENUM -%token EXTERN -%token FALSE -%token FINAL -%token FN -%token FOR -%token IF -%token IMPL -%token IN -%token LET -%token LOOP -%token MACRO -%token MATCH -%token MOD -%token MOVE -%token MUT -%token OFFSETOF -%token OVERRIDE -%token PRIV -%token PUB -%token PURE -%token REF -%token RETURN -%token SIZEOF -%token STRUCT -%token SUPER -%token UNION -%token UNSIZED -%token TRUE -%token TRAIT -%token TYPE -%token UNSAFE -%token VIRTUAL -%token YIELD -%token DEFAULT -%token USE -%token WHILE -%token CONTINUE -%token PROC -%token BOX -%token CONST -%token WHERE -%token TYPEOF -%token INNER_DOC_COMMENT -%token OUTER_DOC_COMMENT - -%token SHEBANG -%token SHEBANG_LINE -%token STATIC_LIFETIME - - /* - Quoting from the Bison manual: - - "Finally, the resolution of conflicts works by comparing the precedence - of the rule being considered with that of the lookahead token. If the - token's precedence is higher, the choice is to shift. If the rule's - precedence is higher, the choice is to reduce. If they have equal - precedence, the choice is made based on the associativity of that - precedence level. The verbose output file made by ā-vā (see Invoking - Bison) says how each conflict was resolved" - */ - -// We expect no shift/reduce or reduce/reduce conflicts in this grammar; -// all potential ambiguities are scrutinized and eliminated manually. -%expect 0 - -// fake-precedence symbol to cause '|' bars in lambda context to parse -// at low precedence, permit things like |x| foo = bar, where '=' is -// otherwise lower-precedence than '|'. Also used for proc() to cause -// things like proc() a + b to parse as proc() { a + b }. -%precedence LAMBDA - -%precedence SELF - -// MUT should be lower precedence than IDENT so that in the pat rule, -// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]" -%precedence MUT - -// IDENT needs to be lower than '{' so that 'foo {' is shifted when -// trying to decide if we've got a struct-construction expr (esp. in -// contexts like 'if foo { .') -// -// IDENT also needs to be lower precedence than '<' so that '<' in -// 'foo:bar . <' is shifted (in a trait reference occurring in a -// bounds list), parsing as foo:(bar<baz>) rather than (foo:bar)<baz>. -%precedence IDENT - // Put the weak keywords that can be used as idents here as well -%precedence CATCH -%precedence DEFAULT -%precedence UNION - -// A couple fake-precedence symbols to use in rules associated with + -// and < in trailing type contexts. These come up when you have a type -// in the RHS of operator-AS, such as "foo as bar<baz>". The "<" there -// has to be shifted so the parser keeps trying to parse a type, even -// though it might well consider reducing the type "bar" and then -// going on to "<" as a subsequent binop. The "+" case is with -// trailing type-bounds ("foo as bar:A+B"), for the same reason. -%precedence SHIFTPLUS - -%precedence MOD_SEP -%precedence RARROW ':' - -// In where clauses, "for" should have greater precedence when used as -// a higher ranked constraint than when used as the beginning of a -// for_in_type (which is a ty) -%precedence FORTYPE -%precedence FOR - -// Binops & unops, and their precedences -%precedence '?' -%precedence BOX -%nonassoc DOTDOT - -// RETURN needs to be lower-precedence than tokens that start -// prefix_exprs -%precedence RETURN YIELD - -%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ -%right LARROW -%left OROR -%left ANDAND -%left EQEQ NE -%left '<' '>' LE GE -%left '|' -%left '^' -%left '&' -%left SHL SHR -%left '+' '-' -%precedence AS -%left '*' '/' '%' -%precedence '!' - -%precedence '{' '[' '(' '.' - -%precedence RANGE - -%start crate - -%% - -//////////////////////////////////////////////////////////////////////// -// Part 1: Items and attributes -//////////////////////////////////////////////////////////////////////// - -crate -: maybe_shebang inner_attrs maybe_mod_items { mk_node("crate", 2, $2, $3); } -| maybe_shebang maybe_mod_items { mk_node("crate", 1, $2); } -; - -maybe_shebang -: SHEBANG_LINE -| %empty -; - -maybe_inner_attrs -: inner_attrs -| %empty { $$ = mk_none(); } -; - -inner_attrs -: inner_attr { $$ = mk_node("InnerAttrs", 1, $1); } -| inner_attrs inner_attr { $$ = ext_node($1, 1, $2); } -; - -inner_attr -: SHEBANG '[' meta_item ']' { $$ = mk_node("InnerAttr", 1, $3); } -| INNER_DOC_COMMENT { $$ = mk_node("InnerAttr", 1, mk_node("doc-comment", 1, mk_atom(yytext))); } -; - -maybe_outer_attrs -: outer_attrs -| %empty { $$ = mk_none(); } -; - -outer_attrs -: outer_attr { $$ = mk_node("OuterAttrs", 1, $1); } -| outer_attrs outer_attr { $$ = ext_node($1, 1, $2); } -; - -outer_attr -: '#' '[' meta_item ']' { $$ = $3; } -| OUTER_DOC_COMMENT { $$ = mk_node("doc-comment", 1, mk_atom(yytext)); } -; - -meta_item -: ident { $$ = mk_node("MetaWord", 1, $1); } -| ident '=' lit { $$ = mk_node("MetaNameValue", 2, $1, $3); } -| ident '(' meta_seq ')' { $$ = mk_node("MetaList", 2, $1, $3); } -| ident '(' meta_seq ',' ')' { $$ = mk_node("MetaList", 2, $1, $3); } -; - -meta_seq -: %empty { $$ = mk_none(); } -| meta_item { $$ = mk_node("MetaItems", 1, $1); } -| meta_seq ',' meta_item { $$ = ext_node($1, 1, $3); } -; - -maybe_mod_items -: mod_items -| %empty { $$ = mk_none(); } -; - -mod_items -: mod_item { $$ = mk_node("Items", 1, $1); } -| mod_items mod_item { $$ = ext_node($1, 1, $2); } -; - -attrs_and_vis -: maybe_outer_attrs visibility { $$ = mk_node("AttrsAndVis", 2, $1, $2); } -; - -mod_item -: attrs_and_vis item { $$ = mk_node("Item", 2, $1, $2); } -; - -// items that can appear outside of a fn block -item -: stmt_item -| item_macro -; - -// items that can appear in "stmts" -stmt_item -: item_static -| item_const -| item_type -| block_item -| view_item -; - -item_static -: STATIC ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $2, $4, $6); } -| STATIC MUT ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $3, $5, $7); } -; - -item_const -: CONST ident ':' ty '=' expr ';' { $$ = mk_node("ItemConst", 3, $2, $4, $6); } -; - -item_macro -: path_expr '!' maybe_ident parens_delimited_token_trees ';' { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -; - -view_item -: use_item -| extern_fn_item -| EXTERN CRATE ident ';' { $$ = mk_node("ViewItemExternCrate", 1, $3); } -| EXTERN CRATE ident AS ident ';' { $$ = mk_node("ViewItemExternCrate", 2, $3, $5); } -; - -extern_fn_item -: EXTERN maybe_abi item_fn { $$ = mk_node("ViewItemExternFn", 2, $2, $3); } -; - -use_item -: USE view_path ';' { $$ = mk_node("ViewItemUse", 1, $2); } -; - -view_path -: path_no_types_allowed { $$ = mk_node("ViewPathSimple", 1, $1); } -| path_no_types_allowed MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 2, $1, mk_atom("ViewPathListEmpty")); } -| MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 1, mk_atom("ViewPathListEmpty")); } -| path_no_types_allowed MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '*' { $$ = mk_node("ViewPathGlob", 1, $1); } -| MOD_SEP '*' { $$ = mk_atom("ViewPathGlob"); } -| '*' { $$ = mk_atom("ViewPathGlob"); } -| '{' '}' { $$ = mk_atom("ViewPathListEmpty"); } -| '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $2); } -| '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); } -| path_no_types_allowed AS ident { $$ = mk_node("ViewPathSimple", 2, $1, $3); } -; - -block_item -: item_fn -| item_unsafe_fn -| item_mod -| item_foreign_mod { $$ = mk_node("ItemForeignMod", 1, $1); } -| item_struct -| item_enum -| item_union -| item_trait -| item_impl -; - -maybe_ty_ascription -: ':' ty_sum { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_init_expr -: '=' expr { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -// structs -item_struct -: STRUCT ident generic_params maybe_where_clause struct_decl_args -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 3, $2, $3, $4); -} -; - -struct_decl_args -: '{' struct_decl_fields '}' { $$ = $2; } -| '{' struct_decl_fields ',' '}' { $$ = $2; } -; - -struct_tuple_args -: '(' struct_tuple_fields ')' { $$ = $2; } -| '(' struct_tuple_fields ',' ')' { $$ = $2; } -; - -struct_decl_fields -: struct_decl_field { $$ = mk_node("StructFields", 1, $1); } -| struct_decl_fields ',' struct_decl_field { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -struct_decl_field -: attrs_and_vis ident ':' ty_sum { $$ = mk_node("StructField", 3, $1, $2, $4); } -; - -struct_tuple_fields -: struct_tuple_field { $$ = mk_node("StructFields", 1, $1); } -| struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -struct_tuple_field -: attrs_and_vis ty_sum { $$ = mk_node("StructField", 2, $1, $2); } -; - -// enums -item_enum -: ENUM ident generic_params maybe_where_clause '{' enum_defs '}' { $$ = mk_node("ItemEnum", 0); } -| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node("ItemEnum", 0); } -; - -enum_defs -: enum_def { $$ = mk_node("EnumDefs", 1, $1); } -| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -enum_def -: attrs_and_vis ident enum_args { $$ = mk_node("EnumDef", 3, $1, $2, $3); } -; - -enum_args -: '{' struct_decl_fields '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '{' struct_decl_fields ',' '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '(' maybe_ty_sums ')' { $$ = mk_node("EnumArgs", 1, $2); } -| '=' expr { $$ = mk_node("EnumArgs", 1, $2); } -| %empty { $$ = mk_none(); } -; - -// unions -item_union -: UNION ident generic_params maybe_where_clause '{' struct_decl_fields '}' { $$ = mk_node("ItemUnion", 0); } -| UNION ident generic_params maybe_where_clause '{' struct_decl_fields ',' '}' { $$ = mk_node("ItemUnion", 0); } - -item_mod -: MOD ident ';' { $$ = mk_node("ItemMod", 1, $2); } -| MOD ident '{' maybe_mod_items '}' { $$ = mk_node("ItemMod", 2, $2, $4); } -| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node("ItemMod", 3, $2, $4, $5); } -; - -item_foreign_mod -: EXTERN maybe_abi '{' maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 1, $4); } -| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 2, $4, $5); } -; - -maybe_abi -: str -| %empty { $$ = mk_none(); } -; - -maybe_foreign_items -: foreign_items -| %empty { $$ = mk_none(); } -; - -foreign_items -: foreign_item { $$ = mk_node("ForeignItems", 1, $1); } -| foreign_items foreign_item { $$ = ext_node($1, 1, $2); } -; - -foreign_item -: attrs_and_vis STATIC item_foreign_static { $$ = mk_node("ForeignItem", 2, $1, $3); } -| attrs_and_vis item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $2); } -| attrs_and_vis UNSAFE item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $3); } -; - -item_foreign_static -: maybe_mut ident ':' ty ';' { $$ = mk_node("StaticItem", 3, $1, $2, $4); } -; - -item_foreign_fn -: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node("ForeignFn", 4, $2, $3, $4, $5); } -; - -fn_decl_allow_variadic -: fn_params_allow_variadic ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params_allow_variadic -: '(' ')' { $$ = mk_none(); } -| '(' params ')' { $$ = $2; } -| '(' params ',' ')' { $$ = $2; } -| '(' params ',' DOTDOTDOT ')' { $$ = $2; } -; - -visibility -: PUB { $$ = mk_atom("Public"); } -| %empty { $$ = mk_atom("Inherited"); } -; - -idents_or_self -: ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); } -| idents_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } -| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } -; - -ident_or_self -: ident -| SELF { $$ = mk_atom(yytext); } -; - -item_type -: TYPE ident generic_params maybe_where_clause '=' ty_sum ';' { $$ = mk_node("ItemTy", 4, $2, $3, $4, $6); } -; - -for_sized -: FOR '?' ident { $$ = mk_node("ForSized", 1, $3); } -| FOR ident '?' { $$ = mk_node("ForSized", 1, $2); } -| %empty { $$ = mk_none(); } -; - -item_trait -: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}' -{ - $$ = mk_node("ItemTrait", 7, $1, $3, $4, $5, $6, $7, $9); -} -; - -maybe_trait_items -: trait_items -| %empty { $$ = mk_none(); } -; - -trait_items -: trait_item { $$ = mk_node("TraitItems", 1, $1); } -| trait_items trait_item { $$ = ext_node($1, 1, $2); } -; - -trait_item -: trait_const -| trait_type -| trait_method -| maybe_outer_attrs item_macro { $$ = mk_node("TraitMacroItem", 2, $1, $2); } -; - -trait_const -: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 4, $1, $3, $4, $5); } -; - -maybe_const_default -: '=' expr { $$ = mk_node("ConstDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -trait_type -: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); } -; - -maybe_unsafe -: UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } -; - -maybe_default_maybe_unsafe -: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); } -| DEFAULT { $$ = mk_atom("Default"); } -| UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } - -trait_method -: type_method { $$ = mk_node("Required", 1, $1); } -| method { $$ = mk_node("Provided", 1, $1); } -; - -type_method -: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7); -} -| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 6, $1, $3, $5, $6, $7, $8); -} -| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9); -} -; - -method -: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); -} -| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $3, $5, $6, $7, $8, $9); -} -| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -; - -impl_method -: attrs_and_vis maybe_default maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $3, $5, $6, $7, $8, $9); -} -| attrs_and_vis maybe_default CONST maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -| attrs_and_vis maybe_default maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 9, $1, $2, $3, $5, $7, $8, $9, $10, $11); -} -; - -// There are two forms of impl: -// -// impl (<...>)? TY { ... } -// impl (<...>)? TRAIT for TY { ... } -// -// Unfortunately since TY can begin with '<' itself -- as part of a -// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL: -// should we reduce one of the early rules of TY (such as maybe_once) -// or shall we continue shifting into the generic_params list for the -// impl? -// -// The production parser disambiguates a different case here by -// permitting / requiring the user to provide parens around types when -// they are ambiguous with traits. We do the same here, regrettably, -// by splitting ty into ty and ty_prim. -item_impl -: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); -} -| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); -} -| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); -} -| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); -} -| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); -} -| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); -} -; - -maybe_impl_items -: impl_items -| %empty { $$ = mk_none(); } -; - -impl_items -: impl_item { $$ = mk_node("ImplItems", 1, $1); } -| impl_item impl_items { $$ = ext_node($1, 1, $2); } -; - -impl_item -: impl_method -| attrs_and_vis item_macro { $$ = mk_node("ImplMacroItem", 2, $1, $2); } -| impl_const -| impl_type -; - -maybe_default -: DEFAULT { $$ = mk_atom("Default"); } -| %empty { $$ = mk_none(); } -; - -impl_const -: attrs_and_vis maybe_default item_const { $$ = mk_node("ImplConst", 3, $1, $2, $3); } -; - -impl_type -: attrs_and_vis maybe_default TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 5, $1, $2, $4, $5, $7); } -; - -item_fn -: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6); -} -| CONST FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemFn", 5, $3, $4, $5, $6, $7); -} -; - -item_unsafe_fn -: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7); -} -| CONST UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 5, $4, $5, $6, $7, $8); -} -| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9); -} -; - -fn_decl -: fn_params ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self -: fn_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self_allow_anon_params -: fn_anon_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params -: '(' maybe_params ')' { $$ = $2; } -; - -fn_anon_params -: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); } -| '(' ')' { $$ = mk_none(); } -; - -fn_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfLower", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -fn_anon_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfLower", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_anon_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -maybe_params -: params -| params ',' -| %empty { $$ = mk_none(); } -; - -params -: param { $$ = mk_node("Args", 1, $1); } -| params ',' param { $$ = ext_node($1, 1, $3); } -; - -param -: pat ':' ty_sum { $$ = mk_node("Arg", 2, $1, $3); } -; - -inferrable_params -: inferrable_param { $$ = mk_node("InferrableParams", 1, $1); } -| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); } -; - -inferrable_param -: pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); } -; - -maybe_comma_params -: ',' { $$ = mk_none(); } -| ',' params { $$ = $2; } -| ',' params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_comma_anon_params -: ',' { $$ = mk_none(); } -| ',' anon_params { $$ = $2; } -| ',' anon_params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_anon_params -: anon_params -| anon_params ',' -| %empty { $$ = mk_none(); } -; - -anon_params -: anon_param { $$ = mk_node("Args", 1, $1); } -| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); } -; - -// anon means it's allowed to be anonymous (type-only), but it can -// still have a name -anon_param -: named_arg ':' ty { $$ = mk_node("Arg", 2, $1, $3); } -| ty -; - -anon_params_allow_variadic_tail -: ',' DOTDOTDOT { $$ = mk_none(); } -| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node("Args", 2, $2, $3); } -| %empty { $$ = mk_none(); } -; - -named_arg -: ident -| UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' ident { $$ = $2; } -| '&' UNDERSCORE { $$ = mk_atom("PatWild"); } -| ANDAND ident { $$ = $2; } -| ANDAND UNDERSCORE { $$ = mk_atom("PatWild"); } -| MUT ident { $$ = $2; } -; - -ret_ty -: RARROW '!' { $$ = mk_none(); } -| RARROW ty { $$ = mk_node("ret-ty", 1, $2); } -| %prec IDENT %empty { $$ = mk_none(); } -; - -generic_params -: '<' '>' { $$ = mk_node("Generics", 2, mk_none(), mk_none()); } -| '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' ty_params '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' ty_params '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| %empty { $$ = mk_none(); } -; - -maybe_where_clause -: %empty { $$ = mk_none(); } -| where_clause -; - -where_clause -: WHERE where_predicates { $$ = mk_node("WhereClause", 1, $2); } -| WHERE where_predicates ',' { $$ = mk_node("WhereClause", 1, $2); } -; - -where_predicates -: where_predicate { $$ = mk_node("WherePredicates", 1, $1); } -| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); } -; - -where_predicate -: maybe_for_lifetimes lifetime ':' bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -; - -maybe_for_lifetimes -: FOR '<' lifetimes '>' { $$ = mk_none(); } -| %prec FORTYPE %empty { $$ = mk_none(); } - -ty_params -: ty_param { $$ = mk_node("TyParams", 1, $1); } -| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); } -; - -// A path with no type parameters; e.g. `foo::bar::Baz` -// -// These show up in 'use' view-items, because these are processed -// without respect to types. -path_no_types_allowed -: ident { $$ = mk_node("ViewPath", 1, $1); } -| MOD_SEP ident { $$ = mk_node("ViewPath", 1, $2); } -| SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| MOD_SEP SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| SUPER { $$ = mk_node("ViewPath", 1, mk_atom("Super")); } -| MOD_SEP SUPER { $$ = mk_node("ViewPath", 1, mk_atom("Super")); } -| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); } -; - -// A path with a lifetime and type parameters, with no double colons -// before the type parameters; e.g. `foo::bar<'a>::Baz<T>` -// -// These show up in "trait references", the components of -// type-parameter bounds lists, as well as in the prefix of the -// path_generic_args_and_bounds rule, which is the full form of a -// named typed expression. -// -// They do not have (nor need) an extra '::' before '<' because -// unlike in expr context, there are no "less-than" type exprs to -// be ambiguous with. -path_generic_args_without_colons -: %prec IDENT - ident { $$ = mk_node("components", 1, $1); } -| %prec IDENT - ident generic_args { $$ = mk_node("components", 2, $1, $2); } -| %prec IDENT - ident '(' maybe_ty_sums ')' ret_ty { $$ = mk_node("components", 2, $1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident generic_args { $$ = ext_node($1, 2, $3, $4); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); } -; - -generic_args -: '<' generic_values '>' { $$ = $2; } -| '<' generic_values SHR { push_back('>'); $$ = $2; } -| '<' generic_values GE { push_back('='); $$ = $2; } -| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -// If generic_args starts with "<<", the first arg must be a -// TyQualifiedPath because that's the only type that can start with a -// '<'. This rule parses that as the first ty_sum and then continues -// with the rest of generic_values. -| SHL ty_qualified_path_and_generic_values '>' { $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHR { push_back('>'); $$ = $2; } -| SHL ty_qualified_path_and_generic_values GE { push_back('='); $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -; - -generic_values -: maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 1, $1); } -; - -maybe_ty_sums_and_or_bindings -: ty_sums -| ty_sums ',' -| ty_sums ',' bindings { $$ = mk_node("TySumsAndBindings", 2, $1, $3); } -| bindings -| bindings ',' -| %empty { $$ = mk_none(); } -; - -maybe_bindings -: ',' bindings { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 2: Patterns -//////////////////////////////////////////////////////////////////////// - -pat -: UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' pat { $$ = mk_node("PatRegion", 1, $2); } -| '&' MUT pat { $$ = mk_node("PatRegion", 1, $3); } -| ANDAND pat { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); } -| '(' ')' { $$ = mk_atom("PatUnit"); } -| '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); } -| '[' pat_vec ']' { $$ = mk_node("PatVec", 1, $2); } -| lit_or_path -| lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node("PatRange", 2, $1, $3); } -| path_expr '{' pat_struct '}' { $$ = mk_node("PatStruct", 2, $1, $3); } -| path_expr '(' ')' { $$ = mk_node("PatEnum", 2, $1, mk_none()); } -| path_expr '(' pat_tup ')' { $$ = mk_node("PatEnum", 2, $1, $3); } -| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); } -| binding_mode ident { $$ = mk_node("PatIdent", 2, $1, $2); } -| ident '@' pat { $$ = mk_node("PatIdent", 3, mk_node("BindByValue", 1, mk_atom("MutImmutable")), $1, $3); } -| binding_mode ident '@' pat { $$ = mk_node("PatIdent", 3, $1, $2, $4); } -| BOX pat { $$ = mk_node("PatUniq", 1, $2); } -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("PatQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("PatQualifiedPath", 3, mk_node("PatQualifiedPath", 3, $2, $3, $6), $7, $10); -} -; - -pats_or -: pat { $$ = mk_node("Pats", 1, $1); } -| pats_or '|' pat { $$ = ext_node($1, 1, $3); } -; - -binding_mode -: REF { $$ = mk_node("BindByRef", 1, mk_atom("MutImmutable")); } -| REF MUT { $$ = mk_node("BindByRef", 1, mk_atom("MutMutable")); } -| MUT { $$ = mk_node("BindByValue", 1, mk_atom("MutMutable")); } -; - -lit_or_path -: path_expr { $$ = mk_node("PatLit", 1, $1); } -| lit { $$ = mk_node("PatLit", 1, $1); } -| '-' lit { $$ = mk_node("PatLit", 1, $2); } -; - -pat_field -: ident { $$ = mk_node("PatField", 1, $1); } -| binding_mode ident { $$ = mk_node("PatField", 2, $1, $2); } -| BOX ident { $$ = mk_node("PatField", 2, mk_atom("box"), $2); } -| BOX binding_mode ident { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); } -| ident ':' pat { $$ = mk_node("PatField", 2, $1, $3); } -| binding_mode ident ':' pat { $$ = mk_node("PatField", 3, $1, $2, $4); } -| LIT_INTEGER ':' pat { $$ = mk_node("PatField", 2, mk_atom(yytext), $3); } -; - -pat_fields -: pat_field { $$ = mk_node("PatFields", 1, $1); } -| pat_fields ',' pat_field { $$ = ext_node($1, 1, $3); } -; - -pat_struct -: pat_fields { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' DOTDOT { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); } -| DOTDOT { $$ = mk_node("PatStruct", 1, mk_atom("true")); } -| %empty { $$ = mk_node("PatStruct", 1, mk_none()); } -; - -pat_tup -: pat_tup_elts { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts DOTDOT { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts ',' DOTDOT { $$ = mk_node("PatTup", 2, $1, mk_none()); } -| pat_tup_elts DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, $1, $4); } -| pat_tup_elts DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, $4); } -| pat_tup_elts ',' DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, $1, $5); } -| pat_tup_elts ',' DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, $1, $5); } -| DOTDOT ',' pat_tup_elts { $$ = mk_node("PatTup", 2, mk_none(), $3); } -| DOTDOT ',' pat_tup_elts ',' { $$ = mk_node("PatTup", 2, mk_none(), $3); } -| DOTDOT { $$ = mk_node("PatTup", 2, mk_none(), mk_none()); } -; - -pat_tup_elts -: pat { $$ = mk_node("PatTupElts", 1, $1); } -| pat_tup_elts ',' pat { $$ = ext_node($1, 1, $3); } -; - -pat_vec -: pat_vec_elts { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $5); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $5); } -| DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -| %empty { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -; - -pat_vec_elts -: pat { $$ = mk_node("PatVecElts", 1, $1); } -| pat_vec_elts ',' pat { $$ = ext_node($1, 1, $3); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 3: Types -//////////////////////////////////////////////////////////////////////// - -ty -: ty_prim -| ty_closure -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, mk_node("TyQualifiedPath", 3, $2, $3, $6), $7, $10); } -| '(' ty_sums ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ty_sums ',' ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ')' { $$ = mk_atom("TyNil"); } -; - -ty_prim -: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); } -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); } -| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); } -| %prec IDENT path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $1, $3, $4); } -| %prec IDENT MOD_SEP path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $2, $4, $5); } -| BOX ty { $$ = mk_node("TyBox", 1, $2); } -| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); } -| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); } -| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); } -| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); } -| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); } -| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); } -| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); } -| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); } -| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); } -| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); } -| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); } -| UNDERSCORE { $$ = mk_atom("TyInfer"); } -| ty_bare_fn -| for_in_type -; - -ty_bare_fn -: FN ty_fn_decl { $$ = $2; } -| UNSAFE FN ty_fn_decl { $$ = $3; } -| EXTERN maybe_abi FN ty_fn_decl { $$ = $4; } -| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; } -; - -ty_fn_decl -: generic_params fn_anon_params ret_ty { $$ = mk_node("TyFnDecl", 3, $1, $2, $3); } -; - -ty_closure -: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $3, $5, $6); } -| '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $2, $4, $5); } -| UNSAFE OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $3, $4); } -| OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $2, $3); } -; - -for_in_type -: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); } -; - -for_in_type_suffix -: ty_bare_fn -| trait_ref -| ty_closure -; - -maybe_mut -: MUT { $$ = mk_atom("MutMutable"); } -| %prec MUT %empty { $$ = mk_atom("MutImmutable"); } -; - -maybe_mut_or_const -: MUT { $$ = mk_atom("MutMutable"); } -| CONST { $$ = mk_atom("MutImmutable"); } -| %empty { $$ = mk_atom("MutImmutable"); } -; - -ty_qualified_path_and_generic_values -: ty_qualified_path maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 1, mk_node("TySum", 1, $1)), $2); -} -| ty_qualified_path ',' ty_sums maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 2, $1, $3), $4); -} -; - -ty_qualified_path -: ty_sum AS trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -; - -maybe_ty_sums -: ty_sums -| ty_sums ',' -| %empty { $$ = mk_none(); } -; - -ty_sums -: ty_sum { $$ = mk_node("TySums", 1, $1); } -| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); } -; - -ty_sum -: ty_sum_elt { $$ = mk_node("TySum", 1, $1); } -| ty_sum '+' ty_sum_elt { $$ = ext_node($1, 1, $3); } -; - -ty_sum_elt -: ty -| lifetime -; - -ty_prim_sum -: ty_prim_sum_elt { $$ = mk_node("TySum", 1, $1); } -| ty_prim_sum '+' ty_prim_sum_elt { $$ = ext_node($1, 1, $3); } -; - -ty_prim_sum_elt -: ty_prim -| lifetime -; - -maybe_ty_param_bounds -: ':' ty_param_bounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ty_param_bounds -: boundseq -| %empty { $$ = mk_none(); } -; - -boundseq -: polybound -| boundseq '+' polybound { $$ = ext_node($1, 1, $3); } -; - -polybound -: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); } -| bound -| '?' FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $4, $6); } -| '?' bound { $$ = $2; } -; - -bindings -: binding { $$ = mk_node("Bindings", 1, $1); } -| bindings ',' binding { $$ = ext_node($1, 1, $3); } -; - -binding -: ident '=' ty { mk_node("Binding", 2, $1, $3); } -; - -ty_param -: ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 3, $1, $2, $3); } -| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 4, $1, $3, $4, $5); } -; - -maybe_bounds -: %prec SHIFTPLUS - ':' bounds { $$ = $2; } -| %prec SHIFTPLUS %empty { $$ = mk_none(); } -; - -bounds -: bound { $$ = mk_node("bounds", 1, $1); } -| bounds '+' bound { $$ = ext_node($1, 1, $3); } -; - -bound -: lifetime -| trait_ref -; - -maybe_ltbounds -: %prec SHIFTPLUS - ':' ltbounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ltbounds -: lifetime { $$ = mk_node("ltbounds", 1, $1); } -| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); } -; - -maybe_ty_default -: '=' ty_sum { $$ = mk_node("TyDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -maybe_lifetimes -: lifetimes -| lifetimes ',' -| %empty { $$ = mk_none(); } -; - -lifetimes -: lifetime_and_bounds { $$ = mk_node("Lifetimes", 1, $1); } -| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); } -; - -lifetime_and_bounds -: LIFETIME maybe_ltbounds { $$ = mk_node("lifetime", 2, mk_atom(yytext), $2); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -lifetime -: LIFETIME { $$ = mk_node("lifetime", 1, mk_atom(yytext)); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -trait_ref -: %prec IDENT path_generic_args_without_colons -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; } -; - -//////////////////////////////////////////////////////////////////////// -// Part 4: Blocks, statements, and expressions -//////////////////////////////////////////////////////////////////////// - -inner_attrs_and_block -: '{' maybe_inner_attrs maybe_stmts '}' { $$ = mk_node("ExprBlock", 2, $2, $3); } -; - -block -: '{' maybe_stmts '}' { $$ = mk_node("ExprBlock", 1, $2); } -; - -maybe_stmts -: stmts -| stmts nonblock_expr { $$ = ext_node($1, 1, $2); } -| nonblock_expr -| %empty { $$ = mk_none(); } -; - -// There are two sub-grammars within a "stmts: exprs" derivation -// depending on whether each stmt-expr is a block-expr form; this is to -// handle the "semicolon rule" for stmt sequencing that permits -// writing -// -// if foo { bar } 10 -// -// as a sequence of two stmts (one if-expr stmt, one lit-10-expr -// stmt). Unfortunately by permitting juxtaposition of exprs in -// sequence like that, the non-block expr grammar has to have a -// second limited sub-grammar that excludes the prefix exprs that -// are ambiguous with binops. That is to say: -// -// {10} - 1 -// -// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that -// is to say, two statements rather than one, at least according to -// the mainline rust parser. -// -// So we wind up with a 3-way split in exprs that occur in stmt lists: -// block, nonblock-prefix, and nonblock-nonprefix. -// -// In non-stmts contexts, expr can relax this trichotomy. - -stmts -: stmt { $$ = mk_node("stmts", 1, $1); } -| stmts stmt { $$ = ext_node($1, 1, $2); } -; - -stmt -: maybe_outer_attrs let { $$ = $2; } -| stmt_item -| PUB stmt_item { $$ = $2; } -| outer_attrs stmt_item { $$ = $2; } -| outer_attrs PUB stmt_item { $$ = $3; } -| full_block_expr -| maybe_outer_attrs block { $$ = $2; } -| nonblock_expr ';' -| outer_attrs nonblock_expr ';' { $$ = $2; } -| ';' { $$ = mk_none(); } -; - -maybe_exprs -: exprs -| exprs ',' -| %empty { $$ = mk_none(); } -; - -maybe_expr -: expr -| %empty { $$ = mk_none(); } -; - -exprs -: expr { $$ = mk_node("exprs", 1, $1); } -| exprs ',' expr { $$ = ext_node($1, 1, $3); } -; - -path_expr -: path_generic_args_with_colons -| MOD_SEP path_generic_args_with_colons { $$ = $2; } -| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node("SelfPath", 1, $3); } -; - -// A path with a lifetime and type parameters with double colons before -// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>` -// -// These show up in expr context, in order to disambiguate from "less-than" -// expressions. -path_generic_args_with_colons -: ident { $$ = mk_node("components", 1, $1); } -| SUPER { $$ = mk_atom("Super"); } -| path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| path_generic_args_with_colons MOD_SEP SUPER { $$ = ext_node($1, 1, mk_atom("Super")); } -| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); } -; - -// the braces-delimited macro is a block_expr so it doesn't appear here -macro_expr -: path_expr '!' maybe_ident parens_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -; - -nonblock_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonblock_expr '?' { $$ = mk_node("ExprTry", 1, $1); } -| nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonblock_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonblock_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonblock_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE lifetime { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } -| YIELD { $$ = mk_node("ExprYield", 0); } -| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonblock_expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonblock_expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonblock_expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonblock_expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonblock_expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonblock_expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonblock_expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonblock_expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonblock_expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonblock_expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonblock_expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonblock_expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonblock_expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonblock_expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonblock_expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonblock_expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonblock_expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonblock_expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonblock_expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonblock_expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonblock_expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonblock_expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonblock_expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonblock_expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonblock_expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonblock_expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonblock_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonblock_expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonblock_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| nonblock_expr ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } -| BOX expr { $$ = mk_node("ExprBox", 1, $2); } -| expr_qualified_path -| nonblock_prefix_expr -; - -expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| expr '?' { $$ = mk_node("ExprTry", 1, $1); } -| expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| YIELD { $$ = mk_node("ExprYield", 0); } -| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| expr ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } -| BOX expr { $$ = mk_node("ExprBox", 1, $2); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -expr_nostruct -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| expr_nostruct '?' { $$ = mk_node("ExprTry", 1, $1); } -| expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr_nostruct '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr_nostruct '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr_nostruct '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| YIELD { $$ = mk_node("ExprYield", 0); } -| YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr_nostruct MINUSEQ expr_nostruct { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr_nostruct ANDEQ expr_nostruct { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr_nostruct OREQ expr_nostruct { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr_nostruct PLUSEQ expr_nostruct { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr_nostruct STAREQ expr_nostruct { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr_nostruct SLASHEQ expr_nostruct { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr_nostruct CARETEQ expr_nostruct { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr_nostruct PERCENTEQ expr_nostruct { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr_nostruct OROR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr_nostruct ANDAND expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr_nostruct EQEQ expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr_nostruct NE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr_nostruct '<' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr_nostruct '>' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr_nostruct LE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr_nostruct GE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr_nostruct '|' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr_nostruct '^' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr_nostruct '&' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr_nostruct SHL expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr_nostruct SHR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr_nostruct '+' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr_nostruct '-' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr_nostruct '*' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr_nostruct '/' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr_nostruct '%' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr_nostruct DOTDOT %prec RANGE { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr_nostruct DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr_nostruct AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| expr_nostruct ':' ty { $$ = mk_node("ExprTypeAscr", 2, $1, $3); } -| BOX expr { $$ = mk_node("ExprBox", 1, $2); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr_nostruct -; - -nonblock_prefix_expr_nostruct -: '-' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr_nostruct -| MOVE lambda_expr_nostruct { $$ = $2; } -; - -nonblock_prefix_expr -: '-' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr -| MOVE lambda_expr { $$ = $2; } -; - -expr_qualified_path -: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params -{ - $$ = mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11, $12); -} - -maybe_qpath_params -: MOD_SEP generic_args { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_as_trait_ref -: AS trait_ref { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -lambda_expr -: %prec LAMBDA - OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - '|' '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); } -| %prec LAMBDA - '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); } -| %prec LAMBDA - '|' inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); } -; - -lambda_expr_no_first_bar -: %prec LAMBDA - '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); } -| %prec LAMBDA - inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); } -; - -lambda_expr_nostruct -: %prec LAMBDA - OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); } -| %prec LAMBDA - '|' '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); } -| %prec LAMBDA - '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); } -| %prec LAMBDA - '|' inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); } -; - -lambda_expr_nostruct_no_first_bar -: %prec LAMBDA - '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - inferrable_params '|' ret_ty expr_nostruct { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); } -| %prec LAMBDA - inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); } -; - -vec_expr -: maybe_exprs -| exprs ';' expr { $$ = mk_node("VecRepeat", 2, $1, $3); } -; - -struct_expr_fields -: field_inits -| field_inits ',' -| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); } -| %empty { $$ = mk_none(); } -; - -maybe_field_inits -: field_inits -| field_inits ',' -| %empty { $$ = mk_none(); } -; - -field_inits -: field_init { $$ = mk_node("FieldInits", 1, $1); } -| field_inits ',' field_init { $$ = ext_node($1, 1, $3); } -; - -field_init -: ident { $$ = mk_node("FieldInit", 1, $1); } -| ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); } -| LIT_INTEGER ':' expr { $$ = mk_node("FieldInit", 2, mk_atom(yytext), $3); } -; - -default_field_init -: DOTDOT expr { $$ = mk_node("DefaultFieldInit", 1, $2); } -; - -block_expr -: expr_match -| expr_if -| expr_if_let -| expr_while -| expr_while_let -| expr_loop -| expr_for -| UNSAFE block { $$ = mk_node("UnsafeBlock", 1, $2); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("Macro", 3, $1, $3, $4); } -; - -full_block_expr -: block_expr -| block_expr_dot -; - -block_expr_dot -: block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| block_expr_dot '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| block_expr_dot '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| block_expr_dot '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| block_expr_dot '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -; - -expr_match -: MATCH expr_nostruct '{' '}' { $$ = mk_node("ExprMatch", 1, $2); } -| MATCH expr_nostruct '{' match_clauses '}' { $$ = mk_node("ExprMatch", 2, $2, $4); } -| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, ext_node($4, 1, $5)); } -| MATCH expr_nostruct '{' nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, mk_node("Arms", 1, $4)); } -; - -match_clauses -: match_clause { $$ = mk_node("Arms", 1, $1); } -| match_clauses match_clause { $$ = ext_node($1, 1, $2); } -; - -match_clause -: nonblock_match_clause ',' -| block_match_clause -| block_match_clause ',' -; - -nonblock_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr_dot { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); } -; - -block_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); } -; - -maybe_guard -: IF expr_nostruct { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -expr_if -: IF expr_nostruct block { $$ = mk_node("ExprIf", 2, $2, $3); } -| IF expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIf", 3, $2, $3, $5); } -; - -expr_if_let -: IF LET pat '=' expr_nostruct block { $$ = mk_node("ExprIfLet", 3, $3, $5, $6); } -| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIfLet", 4, $3, $5, $6, $8); } -; - -block_or_if -: block -| expr_if -| expr_if_let -; - -expr_while -: maybe_label WHILE expr_nostruct block { $$ = mk_node("ExprWhile", 3, $1, $3, $4); } -; - -expr_while_let -: maybe_label WHILE LET pat '=' expr_nostruct block { $$ = mk_node("ExprWhileLet", 4, $1, $4, $6, $7); } -; - -expr_loop -: maybe_label LOOP block { $$ = mk_node("ExprLoop", 2, $1, $3); } -; - -expr_for -: maybe_label FOR pat IN expr_nostruct block { $$ = mk_node("ExprForLoop", 4, $1, $3, $5, $6); } -; - -maybe_label -: lifetime ':' -| %empty { $$ = mk_none(); } -; - -let -: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node("DeclLocal", 3, $2, $3, $4); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 5: Macros and misc. rules -//////////////////////////////////////////////////////////////////////// - -lit -: LIT_BYTE { $$ = mk_node("LitByte", 1, mk_atom(yytext)); } -| LIT_CHAR { $$ = mk_node("LitChar", 1, mk_atom(yytext)); } -| LIT_INTEGER { $$ = mk_node("LitInteger", 1, mk_atom(yytext)); } -| LIT_FLOAT { $$ = mk_node("LitFloat", 1, mk_atom(yytext)); } -| TRUE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| FALSE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| str -; - -str -: LIT_STR { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("CookedStr")); } -| LIT_STR_RAW { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("RawStr")); } -| LIT_BYTE_STR { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("ByteStr")); } -| LIT_BYTE_STR_RAW { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("RawByteStr")); } -; - -maybe_ident -: %empty { $$ = mk_none(); } -| ident -; - -ident -: IDENT { $$ = mk_node("ident", 1, mk_atom(yytext)); } -// Weak keywords that can be used as identifiers -| CATCH { $$ = mk_node("ident", 1, mk_atom(yytext)); } -| DEFAULT { $$ = mk_node("ident", 1, mk_atom(yytext)); } -| UNION { $$ = mk_node("ident", 1, mk_atom(yytext)); } -; - -unpaired_token -: SHL { $$ = mk_atom(yytext); } -| SHR { $$ = mk_atom(yytext); } -| LE { $$ = mk_atom(yytext); } -| EQEQ { $$ = mk_atom(yytext); } -| NE { $$ = mk_atom(yytext); } -| GE { $$ = mk_atom(yytext); } -| ANDAND { $$ = mk_atom(yytext); } -| OROR { $$ = mk_atom(yytext); } -| LARROW { $$ = mk_atom(yytext); } -| SHLEQ { $$ = mk_atom(yytext); } -| SHREQ { $$ = mk_atom(yytext); } -| MINUSEQ { $$ = mk_atom(yytext); } -| ANDEQ { $$ = mk_atom(yytext); } -| OREQ { $$ = mk_atom(yytext); } -| PLUSEQ { $$ = mk_atom(yytext); } -| STAREQ { $$ = mk_atom(yytext); } -| SLASHEQ { $$ = mk_atom(yytext); } -| CARETEQ { $$ = mk_atom(yytext); } -| PERCENTEQ { $$ = mk_atom(yytext); } -| DOTDOT { $$ = mk_atom(yytext); } -| DOTDOTDOT { $$ = mk_atom(yytext); } -| MOD_SEP { $$ = mk_atom(yytext); } -| RARROW { $$ = mk_atom(yytext); } -| FAT_ARROW { $$ = mk_atom(yytext); } -| LIT_BYTE { $$ = mk_atom(yytext); } -| LIT_CHAR { $$ = mk_atom(yytext); } -| LIT_INTEGER { $$ = mk_atom(yytext); } -| LIT_FLOAT { $$ = mk_atom(yytext); } -| LIT_STR { $$ = mk_atom(yytext); } -| LIT_STR_RAW { $$ = mk_atom(yytext); } -| LIT_BYTE_STR { $$ = mk_atom(yytext); } -| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); } -| IDENT { $$ = mk_atom(yytext); } -| UNDERSCORE { $$ = mk_atom(yytext); } -| LIFETIME { $$ = mk_atom(yytext); } -| SELF { $$ = mk_atom(yytext); } -| STATIC { $$ = mk_atom(yytext); } -| ABSTRACT { $$ = mk_atom(yytext); } -| ALIGNOF { $$ = mk_atom(yytext); } -| AS { $$ = mk_atom(yytext); } -| BECOME { $$ = mk_atom(yytext); } -| BREAK { $$ = mk_atom(yytext); } -| CATCH { $$ = mk_atom(yytext); } -| CRATE { $$ = mk_atom(yytext); } -| DEFAULT { $$ = mk_atom(yytext); } -| DO { $$ = mk_atom(yytext); } -| ELSE { $$ = mk_atom(yytext); } -| ENUM { $$ = mk_atom(yytext); } -| EXTERN { $$ = mk_atom(yytext); } -| FALSE { $$ = mk_atom(yytext); } -| FINAL { $$ = mk_atom(yytext); } -| FN { $$ = mk_atom(yytext); } -| FOR { $$ = mk_atom(yytext); } -| IF { $$ = mk_atom(yytext); } -| IMPL { $$ = mk_atom(yytext); } -| IN { $$ = mk_atom(yytext); } -| LET { $$ = mk_atom(yytext); } -| LOOP { $$ = mk_atom(yytext); } -| MACRO { $$ = mk_atom(yytext); } -| MATCH { $$ = mk_atom(yytext); } -| MOD { $$ = mk_atom(yytext); } -| MOVE { $$ = mk_atom(yytext); } -| MUT { $$ = mk_atom(yytext); } -| OFFSETOF { $$ = mk_atom(yytext); } -| OVERRIDE { $$ = mk_atom(yytext); } -| PRIV { $$ = mk_atom(yytext); } -| PUB { $$ = mk_atom(yytext); } -| PURE { $$ = mk_atom(yytext); } -| REF { $$ = mk_atom(yytext); } -| RETURN { $$ = mk_atom(yytext); } -| STRUCT { $$ = mk_atom(yytext); } -| SIZEOF { $$ = mk_atom(yytext); } -| SUPER { $$ = mk_atom(yytext); } -| TRUE { $$ = mk_atom(yytext); } -| TRAIT { $$ = mk_atom(yytext); } -| TYPE { $$ = mk_atom(yytext); } -| UNION { $$ = mk_atom(yytext); } -| UNSAFE { $$ = mk_atom(yytext); } -| UNSIZED { $$ = mk_atom(yytext); } -| USE { $$ = mk_atom(yytext); } -| VIRTUAL { $$ = mk_atom(yytext); } -| WHILE { $$ = mk_atom(yytext); } -| YIELD { $$ = mk_atom(yytext); } -| CONTINUE { $$ = mk_atom(yytext); } -| PROC { $$ = mk_atom(yytext); } -| BOX { $$ = mk_atom(yytext); } -| CONST { $$ = mk_atom(yytext); } -| WHERE { $$ = mk_atom(yytext); } -| TYPEOF { $$ = mk_atom(yytext); } -| INNER_DOC_COMMENT { $$ = mk_atom(yytext); } -| OUTER_DOC_COMMENT { $$ = mk_atom(yytext); } -| SHEBANG { $$ = mk_atom(yytext); } -| STATIC_LIFETIME { $$ = mk_atom(yytext); } -| ';' { $$ = mk_atom(yytext); } -| ',' { $$ = mk_atom(yytext); } -| '.' { $$ = mk_atom(yytext); } -| '@' { $$ = mk_atom(yytext); } -| '#' { $$ = mk_atom(yytext); } -| '~' { $$ = mk_atom(yytext); } -| ':' { $$ = mk_atom(yytext); } -| '$' { $$ = mk_atom(yytext); } -| '=' { $$ = mk_atom(yytext); } -| '?' { $$ = mk_atom(yytext); } -| '!' { $$ = mk_atom(yytext); } -| '<' { $$ = mk_atom(yytext); } -| '>' { $$ = mk_atom(yytext); } -| '-' { $$ = mk_atom(yytext); } -| '&' { $$ = mk_atom(yytext); } -| '|' { $$ = mk_atom(yytext); } -| '+' { $$ = mk_atom(yytext); } -| '*' { $$ = mk_atom(yytext); } -| '/' { $$ = mk_atom(yytext); } -| '^' { $$ = mk_atom(yytext); } -| '%' { $$ = mk_atom(yytext); } -; - -token_trees -: %empty { $$ = mk_node("TokenTrees", 0); } -| token_trees token_tree { $$ = ext_node($1, 1, $2); } -; - -token_tree -: delimited_token_trees -| unpaired_token { $$ = mk_node("TTTok", 1, $1); } -; - -delimited_token_trees -: parens_delimited_token_trees -| braces_delimited_token_trees -| brackets_delimited_token_trees -; - -parens_delimited_token_trees -: '(' token_trees ')' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("(")), - $2, - mk_node("TTTok", 1, mk_atom(")"))); -} -; - -braces_delimited_token_trees -: '{' token_trees '}' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("{")), - $2, - mk_node("TTTok", 1, mk_atom("}"))); -} -; - -brackets_delimited_token_trees -: '[' token_trees ']' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("[")), - $2, - mk_node("TTTok", 1, mk_atom("]"))); -} -; diff --git a/src/grammar/raw-string-literal-ambiguity.md b/src/grammar/raw-string-literal-ambiguity.md deleted file mode 100644 index c909f2333148a..0000000000000 --- a/src/grammar/raw-string-literal-ambiguity.md +++ /dev/null @@ -1,64 +0,0 @@ -Rust's lexical grammar is not context-free. Raw string literals are the source -of the problem. Informally, a raw string literal is an `r`, followed by `N` -hashes (where N can be zero), a quote, any characters, then a quote followed -by `N` hashes. Critically, once inside the first pair of quotes, -another quote cannot be followed by `N` consecutive hashes. e.g. -`r###""###"###` is invalid. - -This grammar describes this as best possible: - - R -> 'r' S - S -> '"' B '"' - S -> '#' S '#' - B -> . B - B -> ε - -Where `.` represents any character, and `ε` the empty string. Consider the -string `r#""#"#`. This string is not a valid raw string literal, but can be -accepted as one by the above grammar, using the derivation: - - R : #""#"# - S : ""#" - S : "# - B : # - B : ε - -(Where `T : U` means the rule `T` is applied, and `U` is the remainder of the -string.) The difficulty arises from the fact that it is fundamentally -context-sensitive. In particular, the context needed is the number of hashes. - -To prove that Rust's string literals are not context-free, we will use -the fact that context-free languages are closed under intersection with -regular languages, and the -[pumping lemma for context-free languages](https://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages). - -Consider the regular language `R = r#+""#*"#+`. If Rust's raw string literals are -context-free, then their intersection with `R`, `R'`, should also be context-free. -Therefore, to prove that raw string literals are not context-free, -it is sufficient to prove that `R'` is not context-free. - -The language `R'` is `{r#^n""#^m"#^n | m < n}`. - -Assume `R'` *is* context-free. Then `R'` has some pumping length `p > 0` for which -the pumping lemma applies. Consider the following string `s` in `R'`: - -`r#^p""#^{p-1}"#^p` - -e.g. for `p = 2`: `s = r##""#"##` - -Then `s = uvwxy` for some choice of `uvwxy` such that `vx` is non-empty, -`|vwx| < p+1`, and `uv^iwx^iy` is in `R'` for all `i >= 0`. - -Neither `v` nor `x` can contain a `"` or `r`, as the number of these characters -in any string in `R'` is fixed. So `v` and `x` contain only hashes. -Consequently, of the three sequences of hashes, `v` and `x` combined -can only pump two of them. -If we ever choose the central sequence of hashes, then one of the outer sequences -will not grow when we pump, leading to an imbalance between the outer sequences. -Therefore, we must pump both outer sequences of hashes. However, -there are `p+2` characters between these two sequences of hashes, and `|vwx|` must -be less than `p+1`. Therefore we have a contradiction, and `R'` must not be -context-free. - -Since `R'` is not context-free, it follows that the Rust's raw string literals -must not be context-free. diff --git a/src/grammar/testparser.py b/src/grammar/testparser.py deleted file mode 100755 index 4b5a7fb9e10b5..0000000000000 --- a/src/grammar/testparser.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -# ignore-tidy-linelength - -import sys - -import os -import subprocess -import argparse - -# usage: testparser.py [-h] [-p PARSER [PARSER ...]] -s SOURCE_DIR - -# Parsers should read from stdin and return exit status 0 for a -# successful parse, and nonzero for an unsuccessful parse - -parser = argparse.ArgumentParser() -parser.add_argument('-p', '--parser', nargs='+') -parser.add_argument('-s', '--source-dir', nargs=1, required=True) -args = parser.parse_args(sys.argv[1:]) - -total = 0 -ok = {} -bad = {} -for parser in args.parser: - ok[parser] = 0 - bad[parser] = [] -devnull = open(os.devnull, 'w') -print("\n") - -for base, dirs, files in os.walk(args.source_dir[0]): - for f in filter(lambda p: p.endswith('.rs'), files): - p = os.path.join(base, f) - parse_fail = 'parse-fail' in p - if sys.version_info.major == 3: - lines = open(p, encoding='utf-8').readlines() - else: - lines = open(p).readlines() - if any('ignore-test' in line or 'ignore-lexer-test' in line for line in lines): - continue - total += 1 - for parser in args.parser: - if subprocess.call(parser, stdin=open(p), stderr=subprocess.STDOUT, stdout=devnull) == 0: - if parse_fail: - bad[parser].append(p) - else: - ok[parser] += 1 - else: - if parse_fail: - ok[parser] += 1 - else: - bad[parser].append(p) - parser_stats = ', '.join(['{}: {}'.format(parser, ok[parser]) for parser in args.parser]) - sys.stdout.write("\033[K\r total: {}, {}, scanned {}" - .format(total, os.path.relpath(parser_stats), os.path.relpath(p))) - -devnull.close() - -print("\n") - -for parser in args.parser: - filename = os.path.basename(parser) + '.bad' - print("writing {} files that did not yield the correct result with {} to {}".format(len(bad[parser]), parser, filename)) - with open(filename, "w") as f: - for p in bad[parser]: - f.write(p) - f.write("\n") diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h deleted file mode 100644 index 297e3dc841e87..0000000000000 --- a/src/grammar/tokens.h +++ /dev/null @@ -1,99 +0,0 @@ -enum Token { - SHL = 257, // Parser generators reserve 0-256 for char literals - SHR, - LE, - EQEQ, - NE, - GE, - ANDAND, - OROR, - SHLEQ, - SHREQ, - MINUSEQ, - ANDEQ, - OREQ, - PLUSEQ, - STAREQ, - SLASHEQ, - CARETEQ, - PERCENTEQ, - DOTDOT, - DOTDOTDOT, - MOD_SEP, - LARROW, - RARROW, - FAT_ARROW, - LIT_BYTE, - LIT_CHAR, - LIT_INTEGER, - LIT_FLOAT, - LIT_STR, - LIT_STR_RAW, - LIT_BYTE_STR, - LIT_BYTE_STR_RAW, - IDENT, - UNDERSCORE, - LIFETIME, - - // keywords - SELF, - STATIC, - ABSTRACT, - ALIGNOF, - AS, - BECOME, - BREAK, - CATCH, - CRATE, - DEFAULT, - DO, - ELSE, - ENUM, - EXTERN, - FALSE, - FINAL, - FN, - FOR, - IF, - IMPL, - IN, - LET, - LOOP, - MACRO, - MATCH, - MOD, - MOVE, - MUT, - OFFSETOF, - OVERRIDE, - PRIV, - PUB, - PURE, - REF, - RETURN, - SIZEOF, - STRUCT, - SUPER, - UNION, - TRUE, - TRAIT, - TYPE, - UNSAFE, - UNSIZED, - USE, - VIRTUAL, - WHILE, - YIELD, - CONTINUE, - PROC, - BOX, - CONST, - WHERE, - TYPEOF, - INNER_DOC_COMMENT, - OUTER_DOC_COMMENT, - - SHEBANG, - SHEBANG_LINE, - STATIC_LIFETIME -}; diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index f9c1be20b8bc1..d22420e76dcd4 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -410,7 +410,7 @@ impl<'a> Parser<'a> { &self.input[start..self.input.len()] } - /// Parses an Argument structure, or what's contained within braces inside the format string + /// Parses an `Argument` structure, or what's contained within braces inside the format string. fn argument(&mut self) -> Argument<'a> { let pos = self.position(); let format = self.format(); @@ -464,7 +464,7 @@ impl<'a> Parser<'a> { } /// Parses a format specifier at the current position, returning all of the - /// relevant information in the FormatSpec struct. + /// relevant information in the `FormatSpec` struct. fn format(&mut self) -> FormatSpec<'a> { let mut spec = FormatSpec { fill: None, @@ -571,7 +571,7 @@ impl<'a> Parser<'a> { spec } - /// Parses a Count parameter at the current position. This does not check + /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4310bafd7812a..2238a56b29d04 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -988,10 +988,12 @@ impl<'a> LoweringContext<'a> { // lower attributes (we use the AST version) there is nowhere to keep // the `HirId`s. We don't actually need HIR version of attributes anyway. Attribute { + item: AttrItem { + path: attr.path.clone(), + tokens: self.lower_token_stream(attr.tokens.clone()), + }, id: attr.id, style: attr.style, - path: attr.path.clone(), - tokens: self.lower_token_stream(attr.tokens.clone()), is_sugared_doc: attr.is_sugared_doc, span: attr.span, } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index bdcf9e42ac2a8..23a2f115e05e2 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -196,6 +196,11 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Path { } } +impl_stable_hash_for!(struct ::syntax::ast::AttrItem { + path, + tokens, +}); + impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. @@ -203,19 +208,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute { debug_assert!(!self.is_sugared_doc); let ast::Attribute { + ref item, id: _, style, - ref path, - ref tokens, is_sugared_doc: _, span, } = *self; + item.hash_stable(hcx, hasher); style.hash_stable(hcx, hasher); - path.hash_stable(hcx, hasher); - for tt in tokens.trees() { - tt.hash_stable(hcx, hasher); - } span.hash_stable(hcx, hasher); } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 750ca4e32a64e..b06b63455ba4b 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -23,7 +23,7 @@ use crate::ty::relate::RelateResult; use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, InferConst}; use crate::ty::{FloatVid, IntVid, TyVid, ConstVid}; -use crate::util::nodemap::FxHashMap; +use crate::util::nodemap::{FxHashMap, FxHashSet}; use errors::DiagnosticBuilder; use rustc_data_structures::sync::Lrc; @@ -155,6 +155,8 @@ pub struct InferCtxt<'a, 'tcx> { /// avoid reporting the same error twice. pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>, + pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>, + /// When an error occurs, we want to avoid reporting "derived" /// errors that are due to this original failure. Normally, we /// handle this with the `err_count_on_creation` count, which @@ -538,6 +540,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { selection_cache: Default::default(), evaluation_cache: Default::default(), reported_trait_errors: Default::default(), + reported_closure_mismatch: Default::default(), tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c2d531793372a..a1c97d6c68790 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -24,7 +24,7 @@ use crate::hir::def_id::DefId; use crate::infer::{self, InferCtxt}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::session::DiagnosticMessageId; -use crate::ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use crate::ty::GenericParamDefKind; use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; @@ -37,7 +37,7 @@ use errors::{Applicability, DiagnosticBuilder, pluralise}; use std::fmt; use syntax::ast; use syntax::symbol::{sym, kw}; -use syntax_pos::{DUMMY_SP, Span, ExpnKind}; +use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_fulfillment_errors( @@ -550,7 +550,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - self.note_obligation_cause(&mut err, obligation); + self.note_obligation_cause_code(&mut err, &obligation.predicate, &obligation.cause.code, + &mut vec![]); err.emit(); self.tcx.sess.abort_if_errors(); @@ -885,6 +886,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.hir().span_if_local(did) ).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def + if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { + // We check closures twice, with obligations flowing in different directions, + // but we want to complain about them only once. + return; + } + + self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], _ => vec![ArgKind::empty()], @@ -940,7 +949,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { bug!("overflow should be handled before the `report_selection_error` path"); } }; + self.note_obligation_cause(&mut err, obligation); + err.emit(); } @@ -1604,15 +1615,165 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - fn note_obligation_cause<T>(&self, - err: &mut DiagnosticBuilder<'_>, - obligation: &Obligation<'tcx, T>) - where T: fmt::Display - { - self.note_obligation_cause_code(err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![]); + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) { + // First, attempt to add note to this error with an async-await-specific + // message, and fall back to regular note otherwise. + if !self.note_obligation_cause_for_async_await(err, obligation) { + self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code, + &mut vec![]); + } + } + + /// Adds an async-await specific note to the diagnostic: + /// + /// ```ignore (diagnostic) + /// note: future does not implement `std::marker::Send` because this value is used across an + /// await + /// --> $DIR/issue-64130-non-send-future-diags.rs:15:5 + /// | + /// LL | let g = x.lock().unwrap(); + /// | - has type `std::sync::MutexGuard<'_, u32>` + /// LL | baz().await; + /// | ^^^^^^^^^^^ await occurs here, with `g` maybe used later + /// LL | } + /// | - `g` is later dropped here + /// ``` + /// + /// Returns `true` if an async-await specific note was added to the diagnostic. + fn note_obligation_cause_for_async_await( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \ + obligation.cause.span={:?}", obligation.predicate, obligation.cause.span); + let source_map = self.tcx.sess.source_map(); + + // Look into the obligation predicate to determine the type in the generator which meant + // that the predicate was not satisifed. + let (trait_ref, target_ty) = match obligation.predicate { + ty::Predicate::Trait(trait_predicate) => + (trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()), + _ => return false, + }; + debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty); + + // Attempt to detect an async-await error by looking at the obligation causes, looking + // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to + // be present. + // + // When a future does not implement a trait because of a captured type in one of the + // generators somewhere in the call stack, then the result is a chain of obligations. + // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that + // future is passed as an argument to a function C which requires a `Send` type, then the + // chain looks something like this: + // + // - `BuiltinDerivedObligation` with a generator witness (B) + // - `BuiltinDerivedObligation` with a generator (B) + // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) + // - `BuiltinDerivedObligation` with a generator witness (A) + // - `BuiltinDerivedObligation` with a generator (A) + // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) + // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) + // - `BindingObligation` with `impl_send (Send requirement) + // + // The first obligations in the chain can be used to get the details of the type that is + // captured but the entire chain must be inspected to detect this case. + let mut generator = None; + let mut next_code = Some(&obligation.cause.code); + while let Some(code) = next_code { + debug!("note_obligation_cause_for_async_await: code={:?}", code); + match code { + ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) | + ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { + debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}", + derived_obligation.parent_trait_ref.self_ty().kind); + match derived_obligation.parent_trait_ref.self_ty().kind { + ty::Adt(ty::AdtDef { did, .. }, ..) if + self.tcx.is_diagnostic_item(sym::gen_future, *did) => {}, + ty::Generator(did, ..) => generator = generator.or(Some(did)), + ty::GeneratorWitness(_) | ty::Opaque(..) => {}, + _ => return false, + } + + next_code = Some(derived_obligation.parent_code.as_ref()); + }, + ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..) + if generator.is_some() => break, + _ => return false, + } + } + + let generator_did = generator.expect("can only reach this if there was a generator"); + + // Only continue to add a note if the generator is from an `async` function. + let parent_node = self.tcx.parent(generator_did) + .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did)); + debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node); + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, header, _, _), + .. + })) = parent_node { + debug!("note_obligation_cause_for_async_await: header={:?}", header); + if header.asyncness != hir::IsAsync::Async { + return false; + } + } + + let span = self.tcx.def_span(generator_did); + let tables = self.tcx.typeck_tables_of(generator_did); + debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ", + generator_did, span); + + // Look for a type inside the generator interior that matches the target type to get + // a span. + let target_span = tables.generator_interior_types.iter() + .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty)) + .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| + (span, source_map.span_to_snippet(*span), scope_span)); + if let Some((target_span, Ok(snippet), scope_span)) = target_span { + // Look at the last interior type to get a span for the `.await`. + let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap(); + let mut span = MultiSpan::from_span(await_span); + span.push_span_label( + await_span, format!("await occurs here, with `{}` maybe used later", snippet)); + + span.push_span_label(*target_span, format!("has type `{}`", target_ty)); + + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + span.push_span_label( + source_map.end_point(*scope_span), + format!("`{}` is later dropped here", snippet), + ); + } + + err.span_note(span, &format!( + "future does not implement `{}` as this value is used across an await", + trait_ref, + )); + + // Add a note for the item obligation that remains - normally a note pointing to the + // bound that introduced the obligation (e.g. `T: Send`). + debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); + self.note_obligation_cause_code( + err, + &obligation.predicate, + next_code.unwrap(), + &mut Vec::new(), + ); + + true + } else { + false + } } fn note_obligation_cause_code<T>(&self, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 34c650b06a586..ffe1a11e81a11 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -288,6 +288,34 @@ pub struct ResolvedOpaqueTy<'tcx> { pub substs: SubstsRef<'tcx>, } +/// Whenever a value may be live across a generator yield, the type of that value winds up in the +/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such +/// captured types that can be useful for diagnostics. In particular, it stores the span that +/// caused a given type to be recorded, along with the scope that enclosed the value (which can +/// be used to find the await that the value is live across). +/// +/// For example: +/// +/// ```ignore (pseudo-Rust) +/// async move { +/// let x: T = ...; +/// foo.await +/// ... +/// } +/// ``` +/// +/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for +/// the scope that contains `x`. +#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, HashStable, PartialEq)] +pub struct GeneratorInteriorTypeCause<'tcx> { + /// Type of the captured binding. + pub ty: Ty<'tcx>, + /// Span of the binding that was captured. + pub span: Span, + /// Span of the scope of the captured binding. + pub scope_span: Option<Span>, +} + #[derive(RustcEncodable, RustcDecodable, Debug)] pub struct TypeckTables<'tcx> { /// The HirId::owner all ItemLocalIds in this table are relative to. @@ -397,6 +425,10 @@ pub struct TypeckTables<'tcx> { /// leading to the member of the struct or tuple that is used instead of the /// entire variable. pub upvar_list: ty::UpvarListMap, + + /// Stores the type, span and optional scope span of all types + /// that are live across the yield of this generator (if a generator). + pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>, } impl<'tcx> TypeckTables<'tcx> { @@ -422,6 +454,7 @@ impl<'tcx> TypeckTables<'tcx> { free_region_map: Default::default(), concrete_opaque_types: Default::default(), upvar_list: Default::default(), + generator_interior_types: Default::default(), } } @@ -729,6 +762,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> { ref free_region_map, ref concrete_opaque_types, ref upvar_list, + ref generator_interior_types, } = *self; @@ -773,6 +807,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> { free_region_map.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); upvar_list.hash_stable(hcx, hasher); + generator_interior_types.hash_stable(hcx, hasher); }) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 269f87c441a82..4b9117f71be5c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -75,7 +75,7 @@ pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, FreeRegionInfo, AllArenas, tls, keep_local}; -pub use self::context::{Lift, TypeckTables, CtxtInterners, GlobalCtxt}; +pub use self::context::{Lift, GeneratorInteriorTypeCause, TypeckTables, CtxtInterners, GlobalCtxt}; pub use self::context::{ UserTypeAnnotationIndex, UserType, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 2a89c94652a24..0c7aa3582ac23 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -99,8 +99,8 @@ impl Margin { // ``` let mut m = Margin { - whitespace_left: if whitespace_left >= 6 { whitespace_left - 6 } else { 0 }, - span_left: if span_left >= 6 { span_left - 6 } else { 0 }, + whitespace_left: whitespace_left.saturating_sub(6), + span_left: span_left.saturating_sub(6), span_right: span_right + 6, computed_left: 0, computed_right: 0, @@ -125,7 +125,7 @@ impl Margin { } else { self.computed_right }; - right < line_len && line_len > self.computed_left + self.column_width + right < line_len && self.computed_left + self.column_width < line_len } fn compute(&mut self, max_line_len: usize) { @@ -167,12 +167,10 @@ impl Margin { } fn right(&self, line_len: usize) -> usize { - if max(line_len, self.computed_left) - self.computed_left <= self.column_width { - line_len - } else if self.computed_right > line_len { + if line_len.saturating_sub(self.computed_left) <= self.column_width { line_len } else { - self.computed_right + min(line_len, self.computed_right) } } } @@ -297,81 +295,82 @@ pub trait Emitter { source_map: &Option<Lrc<SourceMapperDyn>>, span: &mut MultiSpan, always_backtrace: bool) -> bool { - let mut spans_updated = false; + let sm = match source_map { + Some(ref sm) => sm, + None => return false, + }; - if let Some(ref sm) = source_map { - let mut before_after: Vec<(Span, Span)> = vec![]; - let mut new_labels: Vec<(Span, String)> = vec![]; + let mut before_after: Vec<(Span, Span)> = vec![]; + let mut new_labels: Vec<(Span, String)> = vec![]; - // First, find all the spans in <*macros> and point instead at their use site - for sp in span.primary_spans() { - if sp.is_dummy() { + // First, find all the spans in <*macros> and point instead at their use site + for sp in span.primary_spans() { + if sp.is_dummy() { + continue; + } + let call_sp = sm.call_span_if_macro(*sp); + if call_sp != *sp && !always_backtrace { + before_after.push((*sp, call_sp)); + } + let backtrace_len = sp.macro_backtrace().len(); + for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { + // Only show macro locations that are local + // and display them like a span_note + if trace.def_site_span.is_dummy() { continue; } - let call_sp = sm.call_span_if_macro(*sp); - if call_sp != *sp && !always_backtrace { - before_after.push((*sp, call_sp)); + if always_backtrace { + new_labels.push((trace.def_site_span, + format!("in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + }))); } - let backtrace_len = sp.macro_backtrace().len(); - for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { - // Only show macro locations that are local - // and display them like a span_note - if trace.def_site_span.is_dummy() { - continue; - } - if always_backtrace { - new_labels.push((trace.def_site_span, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); - } - // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(trace.def_site_span).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); - if !always_backtrace { - break; - } + // Check to make sure we're not in any <*macros> + if !sm.span_to_filename(trace.def_site_span).is_macros() && + !trace.macro_decl_name.starts_with("desugaring of ") && + !trace.macro_decl_name.starts_with("#[") || + always_backtrace { + new_labels.push((trace.call_site, + format!("in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + }))); + if !always_backtrace { + break; } } } - for (label_span, label_text) in new_labels { - span.push_span_label(label_span, label_text); + } + for (label_span, label_text) in new_labels { + span.push_span_label(label_span, label_text); + } + for sp_label in span.span_labels() { + if sp_label.span.is_dummy() { + continue; } - for sp_label in span.span_labels() { - if sp_label.span.is_dummy() { - continue; - } - if sm.span_to_filename(sp_label.span.clone()).is_macros() && - !always_backtrace - { - let v = sp_label.span.macro_backtrace(); - if let Some(use_site) = v.last() { - before_after.push((sp_label.span.clone(), use_site.call_site.clone())); - } + if sm.span_to_filename(sp_label.span.clone()).is_macros() && + !always_backtrace + { + let v = sp_label.span.macro_backtrace(); + if let Some(use_site) = v.last() { + before_after.push((sp_label.span.clone(), use_site.call_site.clone())); } } - // After we have them, make sure we replace these 'bad' def sites with their use sites - for (before, after) in before_after { - span.replace(before, after); - spans_updated = true; - } + } + // After we have them, make sure we replace these 'bad' def sites with their use sites + let spans_updated = !before_after.is_empty(); + for (before, after) in before_after { + span.replace(before, after); } spans_updated @@ -593,9 +592,9 @@ impl EmitterWriter { let left = margin.left(source_string.len()); // Left trim // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left).fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) - }); + let left = source_string.chars().take(left) + .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) + .sum(); self.draw_line( buffer, @@ -623,18 +622,16 @@ impl EmitterWriter { // 3 | | // 4 | | } // | |_^ test - if line.annotations.len() == 1 { - if let Some(ref ann) = line.annotations.get(0) { - if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { - let style = if ann.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - buffer.putc(line_offset, width_offset + depth - 1, '/', style); - return vec![(depth, style)]; - } + if let [ann] = &line.annotations[..] { + if let AnnotationType::MultilineStart(depth) = ann.annotation_type { + if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { + let style = if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }; + buffer.putc(line_offset, width_offset + depth - 1, '/', style); + return vec![(depth, style)]; } } } @@ -763,11 +760,7 @@ impl EmitterWriter { annotations_position.push((p, annotation)); for (j, next) in annotations.iter().enumerate() { if j > i { - let l = if let Some(ref label) = next.label { - label.len() + 2 - } else { - 0 - }; + let l = next.label.as_ref().map_or(0, |label| label.len() + 2); if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to // avoid situations like: @@ -797,9 +790,7 @@ impl EmitterWriter { } } } - if line_len < p { - line_len = p; - } + line_len = max(line_len, p); } if line_len != 0 { @@ -941,17 +932,9 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, if annotation.end_col + 1 > left { - annotation.end_col + 1 - left - } else { - 0 - }) + (pos + 1, (annotation.end_col + 1).saturating_sub(left)) } else { - (pos + 2, if annotation.start_col > left { - annotation.start_col - left - } else { - 0 - }) + (pos + 2, annotation.start_col.saturating_sub(left)) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, code_offset + col, &label, style); @@ -966,9 +949,9 @@ impl EmitterWriter { // | | | // | | something about `foo` // | something about `fn foo()` - annotations_position.sort_by(|a, b| { - // Decreasing order. When `a` and `b` are the same length, prefer `Primary`. - (a.1.len(), !a.1.is_primary).cmp(&(b.1.len(), !b.1.is_primary)).reverse() + annotations_position.sort_by_key(|(_, ann)| { + // Decreasing order. When annotations share the same length, prefer `Primary`. + (Reverse(ann.len()), ann.is_primary) }); // Write the underlines. @@ -991,11 +974,7 @@ impl EmitterWriter { for p in annotation.start_col..annotation.end_col { buffer.putc( line_offset + 1, - if code_offset + p > left { - code_offset + p - left - } else { - 0 - }, + (code_offset + p).saturating_sub(left), underline, style, ); @@ -1018,40 +997,36 @@ impl EmitterWriter { } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { + let sm = match self.sm { + Some(ref sm) => sm, + None => return 0, + }; + let mut max = 0; - if let Some(ref sm) = self.sm { - for primary_span in msp.primary_spans() { - if !primary_span.is_dummy() { - let hi = sm.lookup_char_pos(primary_span.hi()); - if hi.line > max { - max = hi.line; - } - } + for primary_span in msp.primary_spans() { + if !primary_span.is_dummy() { + let hi = sm.lookup_char_pos(primary_span.hi()); + max = (hi.line).max(max); } - if !self.short_message { - for span_label in msp.span_labels() { - if !span_label.span.is_dummy() { - let hi = sm.lookup_char_pos(span_label.span.hi()); - if hi.line > max { - max = hi.line; - } - } + } + if !self.short_message { + for span_label in msp.span_labels() { + if !span_label.span.is_dummy() { + let hi = sm.lookup_char_pos(span_label.span.hi()); + max = (hi.line).max(max); } } } + max } fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { - let primary = self.get_multispan_max_line_num(span); - let mut max = primary; - - for sub in children { - let sub_result = self.get_multispan_max_line_num(&sub.span); - max = std::cmp::max(sub_result, max); - } - max + children.iter() + .map(|sub| self.get_multispan_max_line_num(&sub.span)) + .max() + .unwrap_or(primary) } /// Adds a left margin to every line but the first, given a padding length and the label being @@ -1081,14 +1056,12 @@ impl EmitterWriter { // `max_line_num_len` let padding = " ".repeat(padding + label.len() + 5); - /// Returns `true` if `style`, or the override if present and the style is `NoStyle`. - fn style_or_override(style: Style, override_style: Option<Style>) -> Style { - if let Some(o) = override_style { - if style == Style::NoStyle { - return o; - } + /// Returns `override` if it is present and `style` is `NoStyle` or `style` otherwise + fn style_or_override(style: Style, override_: Option<Style>) -> Style { + match (style, override_) { + (Style::NoStyle, Some(override_)) => override_, + _ => style, } - style } let mut line_number = 0; @@ -1324,13 +1297,12 @@ impl EmitterWriter { for line in &annotated_file.lines { max_line_len = max(max_line_len, annotated_file.file .get_line(line.line_index - 1) - .map(|s| s.len()) - .unwrap_or(0)); + .map_or(0, |s| s.len())); for ann in &line.annotations { span_right_margin = max(span_right_margin, ann.start_col); span_right_margin = max(span_right_margin, ann.end_col); // FIXME: account for labels not in the same line - let label_right = ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0); + let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1); label_right_margin = max(label_right_margin, ann.end_col + label_right); } } @@ -1459,122 +1431,125 @@ impl EmitterWriter { level: &Level, max_line_num_len: usize, ) -> io::Result<()> { - if let Some(ref sm) = self.sm { - let mut buffer = StyledBuffer::new(); + let sm = match self.sm { + Some(ref sm) => sm, + None => return Ok(()) + }; - // Render the suggestion message - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(level.clone())); - buffer.append(0, ": ", Style::HeaderMsg); + let mut buffer = StyledBuffer::new(); + + // Render the suggestion message + let level_str = level.to_string(); + if !level_str.is_empty() { + buffer.append(0, &level_str, Style::Level(level.clone())); + buffer.append(0, ": ", Style::HeaderMsg); + } + self.msg_to_buffer( + &mut buffer, + &[(suggestion.msg.to_owned(), Style::NoStyle)], + max_line_num_len, + "suggestion", + Some(Style::HeaderMsg), + ); + + // Render the replacements for each suggestion + let suggestions = suggestion.splice_lines(&**sm); + + let mut row_num = 2; + for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) { + // Only show underline if the suggestion spans a single line and doesn't cover the + // entirety of the code output. If you have multiple replacements in the same line + // of code, show the underline. + let show_underline = !(parts.len() == 1 + && parts[0].snippet.trim() == complete.trim()) + && complete.lines().count() == 1; + + let lines = sm.span_to_lines(parts[0].span).unwrap(); + + assert!(!lines.lines.is_empty()); + + let line_start = sm.lookup_char_pos(parts[0].span.lo()).line; + draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); + let mut line_pos = 0; + let mut lines = complete.lines(); + for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { + // Print the span column to avoid confusion + buffer.puts(row_num, + 0, + &self.maybe_anonymized(line_start + line_pos), + Style::LineNumber); + // print the suggestion + draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); + buffer.append(row_num, line, Style::NoStyle); + line_pos += 1; + row_num += 1; } - self.msg_to_buffer( - &mut buffer, - &[(suggestion.msg.to_owned(), Style::NoStyle)], - max_line_num_len, - "suggestion", - Some(Style::HeaderMsg), - ); - - // Render the replacements for each suggestion - let suggestions = suggestion.splice_lines(&**sm); - - let mut row_num = 2; - for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) { - // Only show underline if the suggestion spans a single line and doesn't cover the - // entirety of the code output. If you have multiple replacements in the same line - // of code, show the underline. - let show_underline = !(parts.len() == 1 - && parts[0].snippet.trim() == complete.trim()) - && complete.lines().count() == 1; - - let lines = sm.span_to_lines(parts[0].span).unwrap(); - - assert!(!lines.lines.is_empty()); - - let line_start = sm.lookup_char_pos(parts[0].span.lo()).line; - draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); - let mut line_pos = 0; - let mut lines = complete.lines(); - for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { - // Print the span column to avoid confusion - buffer.puts(row_num, - 0, - &self.maybe_anonymized(line_start + line_pos), - Style::LineNumber); - // print the suggestion - draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); - buffer.append(row_num, line, Style::NoStyle); - line_pos += 1; - row_num += 1; - } - // This offset and the ones below need to be signed to account for replacement code - // that is shorter than the original code. - let mut offset: isize = 0; - // Only show an underline in the suggestions if the suggestion is not the - // entirety of the code being shown and the displayed code is not multiline. - if show_underline { - draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); - for part in parts { - let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; - let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display; - - // Do not underline the leading... - let start = part.snippet.len() - .saturating_sub(part.snippet.trim_start().len()); - // ...or trailing spaces. Account for substitutions containing unicode - // characters. - let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) - }); - - let underline_start = (span_start_pos + start) as isize + offset; - let underline_end = (span_start_pos + start + sub_len) as isize + offset; - for p in underline_start..underline_end { + // This offset and the ones below need to be signed to account for replacement code + // that is shorter than the original code. + let mut offset: isize = 0; + // Only show an underline in the suggestions if the suggestion is not the + // entirety of the code being shown and the displayed code is not multiline. + if show_underline { + draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); + for part in parts { + let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; + let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display; + + // Do not underline the leading... + let start = part.snippet.len() + .saturating_sub(part.snippet.trim_start().len()); + // ...or trailing spaces. Account for substitutions containing unicode + // characters. + let sub_len: usize = part.snippet.trim().chars() + .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) + .sum(); + + let underline_start = (span_start_pos + start) as isize + offset; + let underline_end = (span_start_pos + start + sub_len) as isize + offset; + for p in underline_start..underline_end { + buffer.putc(row_num, + max_line_num_len + 3 + p as usize, + '^', + Style::UnderlinePrimary); + } + // underline removals too + if underline_start == underline_end { + for p in underline_start-1..underline_start+1 { buffer.putc(row_num, max_line_num_len + 3 + p as usize, - '^', - Style::UnderlinePrimary); + '-', + Style::UnderlineSecondary); } - // underline removals too - if underline_start == underline_end { - for p in underline_start-1..underline_start+1 { - buffer.putc(row_num, - max_line_num_len + 3 + p as usize, - '-', - Style::UnderlineSecondary); - } - } - - // length of the code after substitution - let full_sub_len = part.snippet.chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) as isize - }); - - // length of the code to be substituted - let snippet_len = span_end_pos as isize - span_start_pos as isize; - // For multiple substitutions, use the position *after* the previous - // substitutions have happened. - offset += full_sub_len - snippet_len; } - row_num += 1; - } - // if we elided some lines, add an ellipsis - if lines.next().is_some() { - buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); - } else if !show_underline { - draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1); - row_num += 1; + // length of the code after substitution + let full_sub_len = part.snippet.chars() + .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) + .sum::<usize>() as isize; + + // length of the code to be substituted + let snippet_len = span_end_pos as isize - span_start_pos as isize; + // For multiple substitutions, use the position *after* the previous + // substitutions have happened. + offset += full_sub_len - snippet_len; } + row_num += 1; } - if suggestions.len() > MAX_SUGGESTIONS { - let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS); - buffer.puts(row_num, 0, &msg, Style::NoStyle); + + // if we elided some lines, add an ellipsis + if lines.next().is_some() { + buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); + } else if !show_underline { + draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1); + row_num += 1; } - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; } + if suggestions.len() > MAX_SUGGESTIONS { + let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS); + buffer.puts(row_num, 0, &msg, Style::NoStyle); + } + emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) } @@ -1732,7 +1707,7 @@ impl FileWithAnnotatedLines { hi.col_display += 1; } - let ann_type = if lo.line != hi.line { + if lo.line != hi.line { let ml = MultilineAnnotation { depth: 1, line_start: lo.line, @@ -1740,34 +1715,27 @@ impl FileWithAnnotatedLines { start_col: lo.col_display, end_col: hi.col_display, is_primary: span_label.is_primary, - label: span_label.label.clone(), + label: span_label.label, overlaps_exactly: false, }; - multiline_annotations.push((lo.file.clone(), ml.clone())); - AnnotationType::Multiline(ml) + multiline_annotations.push((lo.file, ml)); } else { - AnnotationType::Singleline - }; - let ann = Annotation { - start_col: lo.col_display, - end_col: hi.col_display, - is_primary: span_label.is_primary, - label: span_label.label.clone(), - annotation_type: ann_type, - }; - - if !ann.is_multiline() { + let ann = Annotation { + start_col: lo.col_display, + end_col: hi.col_display, + is_primary: span_label.is_primary, + label: span_label.label, + annotation_type: AnnotationType::Singleline, + }; add_annotation_to_file(&mut output, lo.file, lo.line, ann); - } + }; } } // Find overlapping multiline annotations, put them at different depths multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end)); - for item in multiline_annotations.clone() { - let ann = item.1; - for item in multiline_annotations.iter_mut() { - let ref mut a = item.1; + for (_, ann) in multiline_annotations.clone() { + for (_, a) in multiline_annotations.iter_mut() { // Move all other multiline annotations overlapping with this one // one level to the right. if !(ann.same_span(a)) && @@ -1784,9 +1752,7 @@ impl FileWithAnnotatedLines { let mut max_depth = 0; // max overlapping multiline spans for (file, ann) in multiline_annotations { - if ann.depth > max_depth { - max_depth = ann.depth; - } + max_depth = max(max_depth, ann.depth); let mut end_ann = ann.as_end(); if !ann.overlaps_exactly { // avoid output like diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 8474bae5a71d2..9874c0673cfc9 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -247,7 +247,7 @@ pub fn register_plugins<'a>( rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); if sess.opts.incremental.is_some() { - time(sess, "garbage collect incremental cache directory", || { + time(sess, "garbage-collect incremental cache directory", || { if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { warn!( "Error while trying to garbage collect incremental \ @@ -318,7 +318,7 @@ fn configure_and_expand_inner<'a>( crate_loader: &'a mut CrateLoader<'a>, plugin_info: PluginInfo, ) -> Result<(ast::Crate, Resolver<'a>)> { - time(sess, "pre ast expansion lint checks", || { + time(sess, "pre-AST-expansion lint checks", || { lint::check_ast_crate( sess, &krate, @@ -536,8 +536,8 @@ pub fn lower_to_hir( dep_graph: &DepGraph, krate: &ast::Crate, ) -> Result<hir::map::Forest> { - // Lower ast -> hir - let hir_forest = time(sess, "lowering ast -> hir", || { + // Lower AST to HIR. + let hir_forest = time(sess, "lowering AST -> HIR", || { let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver); if sess.opts.debugging_opts.hir_stats { @@ -757,7 +757,7 @@ pub fn prepare_outputs( if !only_dep_info { if let Some(ref dir) = compiler.output_dir { if fs::create_dir_all(dir).is_err() { - sess.err("failed to find or create the directory specified by --out-dir"); + sess.err("failed to find or create the directory specified by `--out-dir`"); return Err(ErrorReported); } } @@ -830,8 +830,8 @@ pub fn create_global_ctxt( let global_ctxt: Option<GlobalCtxt<'_>>; let arenas = AllArenas::new(); - // Construct the HIR map - let hir_map = time(sess, "indexing hir", || { + // Construct the HIR map. + let hir_map = time(sess, "indexing HIR", || { hir::map::map_crate(sess, cstore, &mut hir_forest, &defs) }); @@ -942,7 +942,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); }); - time(sess, "dumping chalk-like clauses", || { + time(sess, "dumping Chalk-like clauses", || { rustc_traits::lowering::dump_program_clauses(tcx); }); diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs index 3d3a020ef0c8e..0540c95d3ded3 100644 --- a/src/librustc_macros/src/lib.rs +++ b/src/librustc_macros/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(proc_macro_hygiene)] #![allow(rustc::default_hash_types)] #![recursion_limit="128"] diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index fd6744da06067..b8e2700803a5d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -952,8 +952,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.sess.span_warn( span, "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default. Only `?Sized` is supported", + this does nothing because the given bound is not \ + a default; only `?Sized` is supported", ); } } diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index d2d3854d2758c..4608eb51df74e 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -14,7 +14,7 @@ use crate::util::nodemap::FxHashMap; struct InteriorVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, - types: FxHashMap<Ty<'tcx>, usize>, + types: FxHashMap<ty::GeneratorInteriorTypeCause<'tcx>, usize>, region_scope_tree: &'tcx region::ScopeTree, expr_count: usize, kind: hir::GeneratorKind, @@ -83,7 +83,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { } else { // Map the type to the number of types added before it let entries = self.types.len(); - self.types.entry(&ty).or_insert(entries); + let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree)); + self.types.entry(ty::GeneratorInteriorTypeCause { + span: source_span, + ty: &ty, + scope_span + }).or_insert(entries); } } else { debug!("no type in expr = {:?}, count = {:?}, span = {:?}", @@ -118,8 +123,12 @@ pub fn resolve_interior<'a, 'tcx>( // Sort types by insertion order types.sort_by_key(|t| t.1); + // Store the generator types and spans into the tables for this generator. + let interior_types = types.iter().cloned().map(|t| t.0).collect::<Vec<_>>(); + visitor.fcx.inh.tables.borrow_mut().generator_interior_types = interior_types; + // Extract type components - let type_list = fcx.tcx.mk_type_list(types.into_iter().map(|t| t.0)); + let type_list = fcx.tcx.mk_type_list(types.into_iter().map(|t| (t.0).ty)); // The types in the generator interior contain lifetimes local to the generator itself, // which should not be exposed outside of the generator. Therefore, we replace these diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2d4d2e32f23db..2b34c24b266d0 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -631,26 +631,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_valid_traits(&self, - err: &mut DiagnosticBuilder<'_>, - valid_out_of_scope_traits: Vec<DefId>) -> bool { + fn suggest_valid_traits( + &self, + err: &mut DiagnosticBuilder<'_>, + valid_out_of_scope_traits: Vec<DefId>, + ) -> bool { if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort(); candidates.dedup(); err.help("items from traits can only be used if the trait is in scope"); - let msg = format!("the following {traits_are} implemented but not in scope, \ - perhaps add a `use` for {one_of_them}:", - traits_are = if candidates.len() == 1 { - "trait is" - } else { - "traits are" - }, - one_of_them = if candidates.len() == 1 { - "it" - } else { - "one of them" - }); + let msg = format!( + "the following {traits_are} implemented but not in scope; \ + perhaps add a `use` for {one_of_them}:", + traits_are = if candidates.len() == 1 { + "trait is" + } else { + "traits are" + }, + one_of_them = if candidates.len() == 1 { + "it" + } else { + "one of them" + }, + ); self.suggest_use_candidates(err, msg, candidates); true diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e3db1c7990d0..be5723959fb22 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2364,7 +2364,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // which diverges, that we are about to lint on. This gives suboptimal diagnostics. // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. if !span.is_desugaring(DesugaringKind::CondTemporary) && - !span.is_desugaring(DesugaringKind::Async) + !span.is_desugaring(DesugaringKind::Async) && + !orig_span.is_desugaring(DesugaringKind::Await) { self.diverges.set(Diverges::WarnedAlways); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index de78c1cdfaba3..99d62d198a9fd 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -58,6 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_free_region_map(); wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); + wbcx.visit_generator_interior_types(); let used_trait_imports = mem::replace( &mut self.tables.borrow_mut().used_trait_imports, @@ -430,6 +431,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_generator_interior_types(&mut self) { + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + self.tables.generator_interior_types = fcx_tables.generator_interior_types.clone(); + } + fn visit_opaque_types(&mut self, span: Span) { for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap(); diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 0406549ff0791..c65f71fb1a4e2 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -26,6 +26,7 @@ pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T: #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")] struct GenFuture<T: Generator<Yield = ()>>(T); // We rely on the fact that async/await futures are immovable in order to create diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7a5c92167bc45..023952042e6d4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2139,18 +2139,29 @@ impl rustc_serialize::Decodable for AttrId { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct AttrItem { + pub path: Path, + pub tokens: TokenStream, +} + /// Metadata associated with an item. /// Doc-comments are promoted to attributes that have `is_sugared_doc = true`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Attribute { + pub item: AttrItem, pub id: AttrId, pub style: AttrStyle, - pub path: Path, - pub tokens: TokenStream, pub is_sugared_doc: bool, pub span: Span, } +// Compatibility impl to avoid churn, consider removing. +impl std::ops::Deref for Attribute { + type Target = AttrItem; + fn deref(&self) -> &Self::Target { &self.item } +} + /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 122cb7fb12b24..7bef693a5be4c 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -9,7 +9,7 @@ pub use StabilityLevel::*; pub use crate::ast::Attribute; use crate::ast; -use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment}; +use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; @@ -255,9 +255,8 @@ impl MetaItem { } } -impl Attribute { - /// Extracts the `MetaItem` from inside this `Attribute`. - pub fn meta(&self) -> Option<MetaItem> { +impl AttrItem { + crate fn meta(&self, span: Span) -> Option<MetaItem> { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { path: self.path.clone(), @@ -269,9 +268,16 @@ impl Attribute { } else { return None; }, - span: self.span, + span, }) } +} + +impl Attribute { + /// Extracts the MetaItem from inside this Attribute. + pub fn meta(&self) -> Option<MetaItem> { + self.item.meta(self.span) + } pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, @@ -333,10 +339,9 @@ impl Attribute { DUMMY_SP, ); f(&Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, id: self.id, style: self.style, - path: meta.path, - tokens: meta.kind.tokens(meta.span), is_sugared_doc: true, span: self.span, }) @@ -384,10 +389,9 @@ crate fn mk_attr_id() -> AttrId { pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { Attribute { + item: AttrItem { path, tokens }, id: mk_attr_id(), style, - path, - tokens, is_sugared_doc: false, span, } @@ -408,10 +412,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); let lit = Lit::from_lit_kind(lit_kind, span); Attribute { + item: AttrItem { + path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), + tokens: MetaItemKind::NameValue(lit).tokens(span), + }, id: mk_attr_id(), style, - path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), - tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, span, } @@ -524,7 +530,7 @@ impl MetaItem { } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), - token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, }, diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 990358c674ff7..2923cc86ba029 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -122,8 +122,8 @@ impl<'a> StripUnconfigured<'a> { while !parser.check(&token::CloseDelim(token::Paren)) { let lo = parser.token.span.lo(); - let (path, tokens) = parser.parse_meta_item_unrestricted()?; - expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); + let item = parser.parse_attr_item()?; + expanded_attrs.push((item, parser.prev_span.with_lo(lo))); parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; } @@ -150,11 +150,10 @@ impl<'a> StripUnconfigured<'a> { // `cfg_attr` inside of another `cfg_attr`. E.g. // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() - .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { + .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { + item, id: attr::mk_attr_id(), style: attr.style, - path, - tokens, is_sugared_doc: false, span, })) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 02e7c6775a49d..bbd8da2acef05 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1,4 +1,4 @@ -use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path}; +use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; use crate::ast::{MacStmtStyle, StmtKind, ItemKind}; use crate::attr::{self, HasAttrs}; use crate::source_map::respan; @@ -555,15 +555,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment { - let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); - if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { - if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else { - emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, - span, GateIssue::Language, - "macro invocations in `extern {}` blocks are experimental"); - } - } - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { let expn_data = self.cx.current_expansion.id.expn_data(); let suggested_limit = self.cx.ecfg.recursion_limit * 2; @@ -578,6 +569,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { FatalError.raise(); } + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); match invoc.kind { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { @@ -625,9 +617,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::Variant(..) => panic!("unexpected annotatable"), })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.tokens, span); + let input = self.extract_proc_macro_attr_input(attr.item.tokens, span); let tok_result = expander.expand(self.cx, span, input, item_tok); - let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span); + let res = + self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span); self.gate_proc_macro_expansion(span, &res); res } @@ -757,14 +750,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { - AstFragmentKind::Expr => "expressions", + AstFragmentKind::Expr | AstFragmentKind::OptExpr => "expressions", AstFragmentKind::Pat => "patterns", - AstFragmentKind::Ty => "types", AstFragmentKind::Stmts => "statements", - AstFragmentKind::Items => return, - AstFragmentKind::TraitItems => return, - AstFragmentKind::ImplItems => return, + AstFragmentKind::Ty | + AstFragmentKind::Items | + AstFragmentKind::TraitItems | + AstFragmentKind::ImplItems | AstFragmentKind::ForeignItems => return, AstFragmentKind::Arms | AstFragmentKind::Fields @@ -1530,11 +1523,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { + item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, span: at.span, id: at.id, style: at.style, - path: meta.path, - tokens: meta.kind.tokens(meta.span), is_sugared_doc: false, }; } else { @@ -1578,9 +1570,6 @@ impl<'feat> ExpansionConfig<'feat> { } } - fn macros_in_extern(&self) -> bool { - self.features.map_or(false, |features| features.macros_in_extern) - } fn proc_macro_hygiene(&self) -> bool { self.features.map_or(false, |features| features.proc_macro_hygiene) } diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index 8f49ba9572d77..d1c50fd85945d 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -924,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal { FatalError.raise() } sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))), - sym::meta => token::NtMeta(panictry!(p.parse_meta_item())), + sym::meta => token::NtMeta(panictry!(p.parse_attr_item())), sym::vis => token::NtVis(panictry!(p.parse_visibility(true))), sym::lifetime => if p.check_lifetime() { token::NtLifetime(p.expect_lifetime().ident) diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs index 5538daf388e2f..cda1ef1436ca1 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/libsyntax/feature_gate/accepted.rs @@ -245,6 +245,8 @@ declare_features! ( (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None), /// Allows attributes in formal function parameters. (accepted, param_attrs, "1.39.0", Some(60406), None), + // Allows macro invocations in `extern {}` blocks. + (accepted, macros_in_extern, "1.40.0", Some(49476), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 38c16dbac6ab7..47ee41f0adc16 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -402,9 +402,6 @@ declare_features! ( /// Allows infering `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - /// Allows macro invocations in `extern {}` blocks. - (active, macros_in_extern, "1.27.0", Some(49476), None), - /// Allows accessing fields of unions inside `const` functions. (active, const_fn_union, "1.27.0", Some(51909), None), diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 80dfe9e5be0ad..3923b9f297b9f 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -550,7 +550,8 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) { } pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { - let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr; + let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span } + = attr; vis.visit_path(path); vis.visit_tts(tokens); vis.visit_span(span); @@ -681,7 +682,10 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(meta) => vis.visit_meta_item(meta), + token::NtMeta(AttrItem { path, tokens }) => { + vis.visit_path(path); + vis.visit_tts(tokens); + } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), token::NtImplItem(item) => diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 44688bd36b5fb..e74f3045db804 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -90,7 +90,7 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, path, tokens, style) = match self.token.kind { + let (span, item, style) = match self.token.kind { token::Pound => { let lo = self.token.span; self.bump(); @@ -107,7 +107,7 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let (path, tokens) = self.parse_meta_item_unrestricted()?; + let item = self.parse_attr_item()?; self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span; @@ -142,7 +142,7 @@ impl<'a> Parser<'a> { } } - (attr_sp, path, tokens, style) + (attr_sp, item, style) } _ => { let token_str = self.this_token_to_string(); @@ -151,10 +151,9 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { + item, id: attr::mk_attr_id(), style, - path, - tokens, is_sugared_doc: false, span, }) @@ -167,19 +166,19 @@ impl<'a> Parser<'a> { /// PATH `[` TOKEN_STREAM `]` /// PATH `{` TOKEN_STREAM `}` /// PATH - /// PATH `=` TOKEN_TREE + /// PATH `=` UNSUFFIXED_LIT /// The delimiters or `=` are still put into the resulting token stream. - pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { - let meta = match self.token.kind { + pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { + let item = match self.token.kind { token::Interpolated(ref nt) => match **nt { - Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + Nonterminal::NtMeta(ref item) => Some(item.clone()), _ => None, }, _ => None, }; - Ok(if let Some(meta) = meta { + Ok(if let Some(item) = item { self.bump(); - (meta.path, meta.kind.tokens(meta.span)) + item } else { let path = self.parse_path(PathStyle::Mod)?; let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || @@ -206,7 +205,7 @@ impl<'a> Parser<'a> { } else { TokenStream::empty() }; - (path, tokens) + ast::AttrItem { path, tokens } }) } @@ -263,7 +262,7 @@ impl<'a> Parser<'a> { /// Matches the following grammar (per RFC 1559). /// - /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token.kind { @@ -274,9 +273,14 @@ impl<'a> Parser<'a> { _ => None, }; - if let Some(meta) = nt_meta { - self.bump(); - return Ok(meta); + if let Some(item) = nt_meta { + return match item.meta(item.path.span) { + Some(meta) => { + self.bump(); + Ok(meta) + } + None => self.unexpected(), + } } let lo = self.token.span; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 66add869359d8..ac3feadce3ae6 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -47,7 +47,7 @@ impl<'a> StringReader<'a> { source_file: Lrc<syntax_pos::SourceFile>, override_span: Option<Span>) -> Self { if source_file.src.is_none() { - sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}", + sess.span_diagnostic.bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index de72f1c4d4906..7eb2a73a11a82 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -18,6 +18,8 @@ type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); +const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; + /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq)] pub enum GateOr { Yes, No } @@ -40,7 +42,7 @@ impl<'a> Parser<'a> { /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P<Pat>> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; let leading_vert_span = self.prev_span; // Parse the possibly-or-pattern. @@ -63,7 +65,7 @@ impl<'a> Parser<'a> { /// Parse the pattern for a function or function pointer parameter. /// Special recovery is provided for or-patterns and leading `|`. pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> { - self.recover_leading_vert("not allowed in a parameter pattern"); + self.recover_leading_vert(None, "not allowed in a parameter pattern"); let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; if let PatKind::Or(..) = &pat.kind { @@ -90,7 +92,7 @@ impl<'a> Parser<'a> { gate_or: GateOr, rc: RecoverComma, ) -> PResult<'a, P<Pat>> { - // Parse the first pattern. + // Parse the first pattern (`p_0`). let first_pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, rc)?; @@ -100,11 +102,12 @@ impl<'a> Parser<'a> { return Ok(first_pat) } + // Parse the patterns `p_1 | ... | p_n` where `n > 0`. let lo = first_pat.span; let mut pats = vec![first_pat]; - while self.eat_or_separator() { + while self.eat_or_separator(Some(lo)) { let pat = self.parse_pat(expected).map_err(|mut err| { - err.span_label(lo, "while parsing this or-pattern starting here"); + err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; self.maybe_recover_unexpected_comma(pat.span, rc)?; @@ -122,11 +125,15 @@ impl<'a> Parser<'a> { /// Eat the or-pattern `|` separator. /// If instead a `||` token is encountered, recover and pretend we parsed `|`. - fn eat_or_separator(&mut self) -> bool { + fn eat_or_separator(&mut self, lo: Option<Span>) -> bool { + if self.recover_trailing_vert(lo) { + return false; + } + match self.token.kind { token::OrOr => { // Found `||`; Recover and pretend we parsed `|`. - self.ban_unexpected_or_or(); + self.ban_unexpected_or_or(lo); self.bump(); true } @@ -134,16 +141,49 @@ impl<'a> Parser<'a> { } } + /// Recover if `|` or `||` is the current token and we have one of the + /// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us. + /// + /// These tokens all indicate that we reached the end of the or-pattern + /// list and can now reliably say that the `|` was an illegal trailing vert. + /// Note that there are more tokens such as `@` for which we know that the `|` + /// is an illegal parse. However, the user's intent is less clear in that case. + fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool { + let is_end_ahead = self.look_ahead(1, |token| match &token.kind { + token::FatArrow // e.g. `a | => 0,`. + | token::Ident(kw::If, false) // e.g. `a | if expr`. + | token::Eq // e.g. `let a | = 0`. + | token::Semi // e.g. `let a |;`. + | token::Colon // e.g. `let a | :`. + | token::Comma // e.g. `let (a |,)`. + | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`. + | token::CloseDelim(token::Paren) // e.g. `let (a | )`. + | token::CloseDelim(token::Brace) => true, // e.g. `let A { f: a | }`. + _ => false, + }); + match (is_end_ahead, &self.token.kind) { + (true, token::BinOp(token::Or)) | (true, token::OrOr) => { + self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern"); + self.bump(); + true + } + _ => false, + } + } + /// We have parsed `||` instead of `|`. Error and suggest `|` instead. - fn ban_unexpected_or_or(&mut self) { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to separate multiple alternative patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + fn ban_unexpected_or_or(&mut self, lo: Option<Span>) { + let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern"); + err.span_suggestion( + self.token.span, + "use a single `|` to separate multiple alternative patterns", + "|".to_owned(), + Applicability::MachineApplicable + ); + if let Some(lo) = lo { + err.span_label(lo, WHILE_PARSING_OR_MSG); + } + err.emit(); } /// Some special error handling for the "top-level" patterns in a match arm, @@ -198,25 +238,38 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P<Pat>> { - self.recover_leading_vert("only allowed in a top-level pattern"); + self.recover_leading_vert(None, "only allowed in a top-level pattern"); self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) } /// Recover if `|` or `||` is here. /// The user is thinking that a leading `|` is allowed in this position. - fn recover_leading_vert(&mut self, ctx: &str) { + fn recover_leading_vert(&mut self, lo: Option<Span>, ctx: &str) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { - let span = self.token.span; - let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); - - self.struct_span_err(span, &format!("a leading `|` is {}", ctx)) - .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) - .emit(); - + self.ban_illegal_vert(lo, "leading", ctx); self.bump(); } } + /// A `|` or possibly `||` token shouldn't be here. Ban it. + fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) { + let span = self.token.span; + let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx)); + err.span_suggestion( + span, + &format!("remove the `{}`", pprust::token_to_string(&self.token)), + String::new(), + Applicability::MachineApplicable, + ); + if let Some(lo) = lo { + err.span_label(lo, WHILE_PARSING_OR_MSG); + } + if let token::OrOr = self.token.kind { + err.note("alternatives in or-patterns are separated with `|`, not `||`"); + } + err.emit(); + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -259,7 +312,7 @@ impl<'a> Parser<'a> { self.bump(); self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")? } - // At this point, token != &, &&, (, [ + // At this point, token != `&`, `&&`, `(`, `[`, `..`, `..=`, or `...`. _ => if self.eat_keyword(kw::Underscore) { // Parse _ PatKind::Wild diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 463ae9124ca23..ca823991a2e5f 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -114,9 +114,9 @@ impl<'a> Parser<'a> { pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { let meta_ident = match self.token.kind { token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref meta) => match meta.kind { - ast::MetaItemKind::Word => Some(meta.path.clone()), - _ => None, + token::NtMeta(ref item) => match item.tokens.is_empty() { + true => Some(item.path.clone()), + false => None, }, _ => None, }, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fe3b51aa246b8..fd78a2bd53442 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -687,7 +687,7 @@ pub enum Nonterminal { NtLifetime(ast::Ident), NtLiteral(P<ast::Expr>), /// Stuff inside brackets for attributes - NtMeta(ast::MetaItem), + NtMeta(ast::AttrItem), NtPath(ast::Path), NtVis(ast::Visibility), NtTT(TokenTree), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4b9c2d13f26b9..7d4ffe493d709 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -324,7 +324,7 @@ fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { crate fn nonterminal_to_string(nt: &Nonterminal) -> String { match *nt { token::NtExpr(ref e) => expr_to_string(e), - token::NtMeta(ref e) => meta_item_to_string(e), + token::NtMeta(ref e) => attr_item_to_string(e), token::NtTy(ref e) => ty_to_string(e), token::NtPath(ref e) => path_to_string(e), token::NtItem(ref e) => item_to_string(e), @@ -412,8 +412,8 @@ pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { to_string(|s| s.print_meta_list_item(li)) } -pub fn meta_item_to_string(mi: &ast::MetaItem) -> String { - to_string(|s| s.print_meta_item(mi)) +fn attr_item_to_string(ai: &ast::AttrItem) -> String { + to_string(|s| s.print_attr_item(ai, ai.path.span)) } pub fn attribute_to_string(attr: &ast::Attribute) -> String { @@ -629,24 +629,28 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - self.ibox(0); - match attr.tokens.trees().next() { - Some(TokenTree::Delimited(_, delim, tts)) => { - self.print_mac_common( - Some(MacHeader::Path(&attr.path)), false, None, delim, tts, true, attr.span - ); - } - tree => { - self.print_path(&attr.path, false, 0); - if tree.is_some() { - self.space(); - self.print_tts(attr.tokens.clone(), true); - } + self.print_attr_item(&attr.item, attr.span); + self.word("]"); + } + } + + fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { + self.ibox(0); + match item.tokens.trees().next() { + Some(TokenTree::Delimited(_, delim, tts)) => { + self.print_mac_common( + Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span + ); + } + tree => { + self.print_path(&item.path, false, 0); + if tree.is_some() { + self.space(); + self.print_tts(item.tokens.clone(), true); } } - self.end(); - self.word("]"); } + self.end(); } fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index bb8e3df3db921..203c4a834899b 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -1,6 +1,6 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. -use syntax::ast::{self, AttrStyle}; +use syntax::ast::{self, AttrItem, AttrStyle}; use syntax::attr::mk_attr; use syntax::panictry; use syntax::parse::{self, token, ParseSess}; @@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); + let AttrItem { path, tokens } = panictry!(parser.parse_attr_item()); let end_span = parser.token.span; if parser.token != token::Eof { parse_sess.span_diagnostic diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 674f17de618e9..6e83e1d3f8d4f 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -884,7 +884,7 @@ pub struct OffsetOverflowError; /// A single source in the `SourceMap`. #[derive(Clone)] pub struct SourceFile { - /// The name of the file that the source came from, source that doesn't + /// The name of the file that the source came from. Source that doesn't /// originate from files has names between angle brackets by convention /// (e.g., `<anon>`). pub name: FileName, @@ -922,9 +922,9 @@ impl Encodable for SourceFile { s.emit_struct_field("name", 0, |s| self.name.encode(s))?; s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?; s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?; - s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?; - s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?; - s.emit_struct_field("lines", 6, |s| { + s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?; + s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?; + s.emit_struct_field("lines", 5, |s| { let lines = &self.lines[..]; // Store the length. s.emit_u32(lines.len() as u32)?; @@ -970,13 +970,13 @@ impl Encodable for SourceFile { Ok(()) })?; - s.emit_struct_field("multibyte_chars", 7, |s| { + s.emit_struct_field("multibyte_chars", 6, |s| { self.multibyte_chars.encode(s) })?; - s.emit_struct_field("non_narrow_chars", 8, |s| { + s.emit_struct_field("non_narrow_chars", 7, |s| { self.non_narrow_chars.encode(s) })?; - s.emit_struct_field("name_hash", 9, |s| { + s.emit_struct_field("name_hash", 8, |s| { self.name_hash.encode(s) }) }) @@ -985,7 +985,6 @@ impl Encodable for SourceFile { impl Decodable for SourceFile { fn decode<D: Decoder>(d: &mut D) -> Result<SourceFile, D::Error> { - d.read_struct("SourceFile", 8, |d| { let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; let name_was_remapped: bool = @@ -993,9 +992,9 @@ impl Decodable for SourceFile { let src_hash: u128 = d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?; let start_pos: BytePos = - d.read_struct_field("start_pos", 4, |d| Decodable::decode(d))?; - let end_pos: BytePos = d.read_struct_field("end_pos", 5, |d| Decodable::decode(d))?; - let lines: Vec<BytePos> = d.read_struct_field("lines", 6, |d| { + d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?; + let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?; + let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| { let num_lines: u32 = Decodable::decode(d)?; let mut lines = Vec::with_capacity(num_lines as usize); @@ -1024,18 +1023,18 @@ impl Decodable for SourceFile { Ok(lines) })?; let multibyte_chars: Vec<MultiByteChar> = - d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?; + d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?; let non_narrow_chars: Vec<NonNarrowChar> = - d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?; + d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?; let name_hash: u128 = - d.read_struct_field("name_hash", 9, |d| Decodable::decode(d))?; + d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?; Ok(SourceFile { name, name_was_remapped, unmapped_path: None, // `crate_of_origin` has to be set by the importer. - // This value matches up with rustc::hir::def_id::INVALID_CRATE. - // That constant is not available here unfortunately :( + // This value matches up with `rustc::hir::def_id::INVALID_CRATE`. + // That constant is not available here, unfortunately. crate_of_origin: std::u32::MAX - 1, start_pos, end_pos, diff --git a/src/test/ui/abi/macros/macros-in-extern.stderr b/src/test/ui/abi/macros/macros-in-extern.stderr deleted file mode 100644 index 6ee33f4ab61f6..0000000000000 --- a/src/test/ui/abi/macros/macros-in-extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:26:5 - | -LL | returns_isize!(rust_get_test_int); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:28:5 - | -LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:30:5 - | -LL | emits_nothing!(); - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs b/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs deleted file mode 100644 index 27efa44f98032..0000000000000 --- a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs +++ /dev/null @@ -1,112 +0,0 @@ -// force-host -// no-prefer-dynamic - -// Proc macros commonly used by tests. -// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros. - -#![crate_type = "proc-macro"] - -extern crate proc_macro; -use proc_macro::TokenStream; - -// Macro that return empty token stream. - -#[proc_macro] -pub fn empty(_: TokenStream) -> TokenStream { - TokenStream::new() -} - -#[proc_macro_attribute] -pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream { - TokenStream::new() -} - -#[proc_macro_derive(Empty, attributes(empty_helper))] -pub fn empty_derive(_: TokenStream) -> TokenStream { - TokenStream::new() -} - -// Macro that panics. - -#[proc_macro] -pub fn panic_bang(_: TokenStream) -> TokenStream { - panic!("panic-bang"); -} - -#[proc_macro_attribute] -pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream { - panic!("panic-attr"); -} - -#[proc_macro_derive(Panic, attributes(panic_helper))] -pub fn panic_derive(_: TokenStream) -> TokenStream { - panic!("panic-derive"); -} - -// Macros that return the input stream. - -#[proc_macro] -pub fn identity(input: TokenStream) -> TokenStream { - input -} - -#[proc_macro_attribute] -pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream { - input -} - -#[proc_macro_derive(Identity, attributes(identity_helper))] -pub fn identity_derive(input: TokenStream) -> TokenStream { - input -} - -// Macros that iterate and re-collect the input stream. - -#[proc_macro] -pub fn recollect(input: TokenStream) -> TokenStream { - input.into_iter().collect() -} - -#[proc_macro_attribute] -pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream { - input.into_iter().collect() -} - -#[proc_macro_derive(Recollect, attributes(recollect_helper))] -pub fn recollect_derive(input: TokenStream) -> TokenStream { - input.into_iter().collect() -} - -// Macros that print their input in the original and re-collected forms (if they differ). - -fn print_helper(input: TokenStream, kind: &str) -> TokenStream { - let input_display = format!("{}", input); - let input_debug = format!("{:#?}", input); - let recollected = input.into_iter().collect(); - let recollected_display = format!("{}", recollected); - let recollected_debug = format!("{:#?}", recollected); - println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display); - if recollected_display != input_display { - println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display); - } - println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug); - if recollected_debug != input_debug { - println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug); - } - recollected -} - -#[proc_macro] -pub fn print_bang(input: TokenStream) -> TokenStream { - print_helper(input, "BANG") -} - -#[proc_macro_attribute] -pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream { - print_helper(input, "ATTR") -} - -#[proc_macro_derive(Print, attributes(print_helper))] -pub fn print_derive(input: TokenStream) -> TokenStream { - print_helper(input, "DERIVE") -} diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.stderr b/src/test/ui/abi/proc-macro/macros-in-extern.stderr deleted file mode 100644 index 6049c2aa4482e..0000000000000 --- a/src/test/ui/abi/proc-macro/macros-in-extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:14:5 - | -LL | #[empty_attr] - | ^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:18:5 - | -LL | #[identity_attr] - | ^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/macros-in-extern.rs:22:5 - | -LL | identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs index 8a1744ed5f8ae..898fe22fa234f 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.rs +++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs @@ -1,26 +1,15 @@ fn main() { f1(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f2(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f3(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f4(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch f5(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g1(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g2(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g3(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch g4(|_: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch - //~^ ERROR type mismatch } // Basic diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index fbe2d192d0cce..9be44c7f44807 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -10,18 +10,7 @@ LL | fn f1<F>(_: F) where F: Fn(&(), &()) {} | -- ------------ required by this bound in `f1` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 - | -LL | f1(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), &()) -> _` -... -LL | fn f1<F>(_: F) where F: Fn(&(), &()) {} - | -- ------------ required by this bound in `f1` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 | LL | f2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -34,17 +23,6 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {} error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 | -LL | f2(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&'a (), &()) -> _` -... -LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {} - | -- --------------- required by this bound in `f2` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 - | LL | f3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | @@ -54,18 +32,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} | -- --------------- required by this bound in `f3` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 - | -LL | f3(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), &()) -> _` -... -LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} - | -- --------------- required by this bound in `f3` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 | LL | f4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -76,18 +43,7 @@ LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {} | -- ----------------------- required by this bound in `f4` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 - | -LL | f4(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), &'r ()) -> _` -... -LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {} - | -- --------------- required by this bound in `f4` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 | LL | f5(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -98,18 +54,7 @@ LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} | -- -------------------------- required by this bound in `f5` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 - | -LL | f5(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&'r (), &'r ()) -> _` -... -LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} - | -- ------------------ required by this bound in `f5` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 | LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -120,18 +65,7 @@ LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {} | -- ------------------------- required by this bound in `g1` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 - | -LL | g1(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` -... -LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {} - | -- ------------------------- required by this bound in `g1` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | LL | g2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -142,18 +76,7 @@ LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {} | -- ---------------- required by this bound in `g2` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 - | -LL | g2(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` -... -LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {} - | -- ---------------- required by this bound in `g2` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 | LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -164,18 +87,7 @@ LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {} | -- ------------------------------------ required by this bound in `g3` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 - | -LL | g3(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` -... -LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {} - | -- ---------------------------- required by this bound in `g3` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | LL | g4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` @@ -186,18 +98,7 @@ LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} | -- --------------------------- required by this bound in `g4` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 - | -LL | g4(|_: (), _: ()| {}); - | ^^ -------------- found signature of `fn((), ()) -> _` - | | - | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` -... -LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} - | -- --------------------------- required by this bound in `g4` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 | LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` @@ -208,18 +109,7 @@ LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {} | -- -------------------------------------------- required by this bound in `h1` error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 - | -LL | h1(|_: (), _: (), _: (), _: ()| {}); - | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` - | | - | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _` -... -LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {} - | -- -------------------------------------------- required by this bound in `h1` - -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 | LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` @@ -229,16 +119,5 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {} | -- --------------------------------------------------------- required by this bound in `h2` -error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 - | -LL | h2(|_: (), _: (), _: (), _: ()| {}); - | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` - | | - | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _` -... -LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {} - | -- ------------------------------------------------ required by this bound in `h2` - -error: aborting due to 22 previous errors +error: aborting due to 11 previous errors diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index 001e0b1cad305..696bd5c39d283 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -9,9 +9,9 @@ LL | assert_send(local_dropped_before_await()); | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `impl std::fmt::Debug` - = note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>` + = note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` @@ -26,9 +26,9 @@ LL | assert_send(non_send_temporary_in_match()); | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` = note: required because it appears within the type `impl std::fmt::Debug` - = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>` + = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` @@ -45,9 +45,9 @@ LL | assert_send(non_sync_with_method_call()); = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write` = note: required because it appears within the type `std::fmt::Formatter<'_>` = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` - = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>` + = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` @@ -68,9 +68,9 @@ LL | assert_send(non_sync_with_method_call()); = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>` = note: required because it appears within the type `std::fmt::Formatter<'_>` = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>` - = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}` - = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]` - = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>` + = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}` + = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]` + = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs new file mode 100644 index 0000000000000..1936d1a2ed56e --- /dev/null +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs @@ -0,0 +1,25 @@ +// edition:2018 + +use std::sync::Mutex; + +fn is_send<T: Send>(t: T) { + +} + +async fn foo() { + bar(&Mutex::new(22)).await; +} + +async fn bar(x: &Mutex<u32>) { + let g = x.lock().unwrap(); + baz().await; +} + +async fn baz() { + +} + +fn main() { + is_send(foo()); + //~^ ERROR `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely [E0277] +} diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr new file mode 100644 index 0000000000000..9e9fc52e30b7f --- /dev/null +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -0,0 +1,23 @@ +error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely + --> $DIR/issue-64130-non-send-future-diags.rs:23:5 + | +LL | fn is_send<T: Send>(t: T) { + | ------- ---- required by this bound in `is_send` +... +LL | is_send(foo()); + | ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>` +note: future does not implement `std::marker::Send` as this value is used across an await + --> $DIR/issue-64130-non-send-future-diags.rs:15:5 + | +LL | let g = x.lock().unwrap(); + | - has type `std::sync::MutexGuard<'_, u32>` +LL | baz().await; + | ^^^^^^^^^^^ await occurs here, with `g` maybe used later +LL | } + | - `g` is later dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/unreachable-lint-1.rs b/src/test/ui/async-await/unreachable-lint-1.rs new file mode 100644 index 0000000000000..d63d643c4e70b --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint-1.rs @@ -0,0 +1,12 @@ +// edition:2018 +#![deny(unreachable_code)] + +async fn foo() { + return; bar().await; + //~^ ERROR unreachable statement +} + +async fn bar() { +} + +fn main() { } diff --git a/src/test/ui/async-await/unreachable-lint-1.stderr b/src/test/ui/async-await/unreachable-lint-1.stderr new file mode 100644 index 0000000000000..382581bf94554 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint-1.stderr @@ -0,0 +1,16 @@ +error: unreachable statement + --> $DIR/unreachable-lint-1.rs:5:13 + | +LL | return; bar().await; + | ------ ^^^^^^^^^^^^ unreachable statement + | | + | any code following this expression is unreachable + | +note: lint level defined here + --> $DIR/unreachable-lint-1.rs:2:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/unreachable-lint.rs b/src/test/ui/async-await/unreachable-lint.rs new file mode 100644 index 0000000000000..ca18cfde4f2f5 --- /dev/null +++ b/src/test/ui/async-await/unreachable-lint.rs @@ -0,0 +1,13 @@ +// check-pass +// edition:2018 +#![deny(unreachable_code)] + +async fn foo() { + endless().await; +} + +async fn endless() -> ! { + loop {} +} + +fn main() { } diff --git a/src/test/ui/cfg/cfg_stmt_expr.rs b/src/test/ui/cfg/cfg_stmt_expr.rs index e466ad69f721c..6381bb2d58877 100644 --- a/src/test/ui/cfg/cfg_stmt_expr.rs +++ b/src/test/ui/cfg/cfg_stmt_expr.rs @@ -57,7 +57,7 @@ fn main() { // check that macro expanded code works macro_rules! if_cfg { - ($cfg:meta $ib:block else $eb:block) => { + ($cfg:meta? $ib:block else $eb:block) => { { let r; #[cfg($cfg)] @@ -69,7 +69,7 @@ fn main() { } } - let n = if_cfg!(unset { + let n = if_cfg!(unset? { 413 } else { 612 diff --git a/src/test/ui/coherence/coherence_inherent.old.stderr b/src/test/ui/coherence/coherence_inherent.old.stderr index 750d243480638..e71547cb89f9c 100644 --- a/src/test/ui/coherence/coherence_inherent.old.stderr +++ b/src/test/ui/coherence/coherence_inherent.old.stderr @@ -5,7 +5,7 @@ LL | s.the_fn(); | ^^^^^^ method not found in `&Lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use Lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent.re.stderr b/src/test/ui/coherence/coherence_inherent.re.stderr index 750d243480638..e71547cb89f9c 100644 --- a/src/test/ui/coherence/coherence_inherent.re.stderr +++ b/src/test/ui/coherence/coherence_inherent.re.stderr @@ -5,7 +5,7 @@ LL | s.the_fn(); | ^^^^^^ method not found in `&Lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use Lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent_cc.old.stderr b/src/test/ui/coherence/coherence_inherent_cc.old.stderr index 59166a4609406..3683943c5c819 100644 --- a/src/test/ui/coherence/coherence_inherent_cc.old.stderr +++ b/src/test/ui/coherence/coherence_inherent_cc.old.stderr @@ -5,7 +5,7 @@ LL | s.the_fn(); | ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use coherence_inherent_cc_lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence_inherent_cc.re.stderr b/src/test/ui/coherence/coherence_inherent_cc.re.stderr index 59166a4609406..3683943c5c819 100644 --- a/src/test/ui/coherence/coherence_inherent_cc.re.stderr +++ b/src/test/ui/coherence/coherence_inherent_cc.re.stderr @@ -5,7 +5,7 @@ LL | s.the_fn(); | ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use coherence_inherent_cc_lib::TheTrait;` error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs deleted file mode 100644 index 125af64fef05c..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![feature(decl_macro)] - -macro_rules! returns_isize( - ($ident:ident) => ( - fn $ident() -> isize; - ) -); - -macro takes_u32_returns_u32($ident:ident) { - fn $ident (arg: u32) -> u32; -} - -macro_rules! emits_nothing( - () => () -); - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental - emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr deleted file mode 100644 index e8b3ab5dda20d..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:19:5 - | -LL | returns_isize!(rust_get_test_int); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:21:5 - | -LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error[E0658]: macro invocations in `extern {}` blocks are experimental - --> $DIR/feature-gate-macros_in_extern.rs:23:5 - | -LL | emits_nothing!(); - | ^^^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/49476 - = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index bc0ce746be925..736369dab8354 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -25,7 +25,7 @@ LL | ().clone() | ^^^^^ method not found in `()` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use std::clone::Clone;` error: aborting due to 3 previous errors diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr index 39e32522c7a76..c3ce484edf7a9 100644 --- a/src/test/ui/hygiene/trait_items.stderr +++ b/src/test/ui/hygiene/trait_items.stderr @@ -8,7 +8,7 @@ LL | pub macro m() { ().f() } | ^ method not found in `()` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use foo::T;` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index be8f3ab1b72e8..f0a03e1be82ac 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -5,7 +5,7 @@ LL | 1u32.method(); | ^^^^^^ method not found in `u32` | = help: items from traits can only be used if the trait is in scope -help: the following traits are implemented but not in scope, perhaps add a `use` for one of them: +help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | LL | use foo::Bar; | @@ -23,7 +23,7 @@ LL | std::rc::Rc::new(&mut Box::new(&1u32)).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u32>>` | = help: items from traits can only be used if the trait is in scope -help: the following traits are implemented but not in scope, perhaps add a `use` for one of them: +help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: | LL | use foo::Bar; | @@ -41,7 +41,7 @@ LL | 'a'.method(); | ^^^^^^ method not found in `char` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use foo::Bar; | @@ -61,7 +61,7 @@ LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use foo::Bar; | @@ -73,7 +73,7 @@ LL | 1i32.method(); | ^^^^^^ method not found in `i32` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use no_method_suggested_traits::foo::PubPub; | @@ -85,7 +85,7 @@ LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use no_method_suggested_traits::foo::PubPub; | diff --git a/src/test/ui/issues/issue-10465.stderr b/src/test/ui/issues/issue-10465.stderr index 413daa6db6787..80ca051ceff0d 100644 --- a/src/test/ui/issues/issue-10465.stderr +++ b/src/test/ui/issues/issue-10465.stderr @@ -5,7 +5,7 @@ LL | b.foo(); | ^^^ method not found in `&b::B` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use a::A;` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr index 3a0ab32dcc66b..2ea9dcbe9d0a4 100644 --- a/src/test/ui/issues/issue-37534.stderr +++ b/src/test/ui/issues/issue-37534.stderr @@ -8,7 +8,7 @@ help: possible better candidate is found in another module, you can import it in LL | use std::hash::Hash; | -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default. Only `?Sized` is supported +warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported --> $DIR/issue-37534.rs:1:12 | LL | struct Foo<T: ?Hash> { } diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index 66680b9936e68..8b173e1b50c1e 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -5,7 +5,7 @@ LL | Command::new("echo").arg("hello").exec(); | ^^^^ method not found in `&mut std::process::Command` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::os::unix::process::CommandExt; | diff --git a/src/test/ui/issues/issue-43189.stderr b/src/test/ui/issues/issue-43189.stderr index 33c3f18650a80..4dae6c1cd158e 100644 --- a/src/test/ui/issues/issue-43189.stderr +++ b/src/test/ui/issues/issue-43189.stderr @@ -5,7 +5,7 @@ LL | ().a(); | ^ method not found in `()` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A; | diff --git a/src/test/ui/issues/issue-50571.rs b/src/test/ui/issues/issue-50571.rs new file mode 100644 index 0000000000000..728c113bdc323 --- /dev/null +++ b/src/test/ui/issues/issue-50571.rs @@ -0,0 +1,6 @@ +trait Foo { + fn foo([a, b]: [i32; 2]) {} + //~^ ERROR: patterns aren't allowed in methods without bodies +} + +fn main() {} diff --git a/src/test/ui/issues/issue-50571.stderr b/src/test/ui/issues/issue-50571.stderr new file mode 100644 index 0000000000000..834635388a066 --- /dev/null +++ b/src/test/ui/issues/issue-50571.stderr @@ -0,0 +1,13 @@ +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/issue-50571.rs:2:12 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^^^^^^ +help: give this argument a name or use an underscore to ignore it + | +LL | fn foo(_: [i32; 2]) {} + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0642`. diff --git a/src/test/ui/issues/issue-58022.rs b/src/test/ui/issues/issue-58022.rs new file mode 100644 index 0000000000000..c6dd45e6cf3e9 --- /dev/null +++ b/src/test/ui/issues/issue-58022.rs @@ -0,0 +1,18 @@ +pub trait Foo: Sized { + const SIZE: usize; + + fn new(slice: &[u8; Foo::SIZE]) -> Self; + //~^ ERROR: type annotations needed: cannot resolve `_: Foo` +} + +pub struct Bar<T: ?Sized>(T); + +impl Bar<[u8]> { + const SIZE: usize = 32; + + fn new(slice: &[u8; Self::SIZE]) -> Self { + Foo(Box::new(*slice)) //~ ERROR: expected function, found trait `Foo` + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-58022.stderr b/src/test/ui/issues/issue-58022.stderr new file mode 100644 index 0000000000000..71bad7b81fa87 --- /dev/null +++ b/src/test/ui/issues/issue-58022.stderr @@ -0,0 +1,19 @@ +error[E0423]: expected function, found trait `Foo` + --> $DIR/issue-58022.rs:14:9 + | +LL | Foo(Box::new(*slice)) + | ^^^ not a function + +error[E0283]: type annotations needed: cannot resolve `_: Foo` + --> $DIR/issue-58022.rs:4:25 + | +LL | const SIZE: usize; + | ------------------ required by `Foo::SIZE` +LL | +LL | fn new(slice: &[u8; Foo::SIZE]) -> Self; + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0283, E0423. +For more information about an error, try `rustc --explain E0283`. diff --git a/src/test/ui/issues/issue-58344.rs b/src/test/ui/issues/issue-58344.rs new file mode 100644 index 0000000000000..99b656d74f505 --- /dev/null +++ b/src/test/ui/issues/issue-58344.rs @@ -0,0 +1,50 @@ +use std::ops::Add; + +trait Trait<T> { + fn get(self) -> T; +} + +struct Holder<T>(T); + +impl<T> Trait<T> for Holder<T> { + fn get(self) -> T { + self.0 + } +} + +enum Either<L, R> { + Left(L), + Right(R), +} + +impl<L, R> Either<L, R> { + fn converge<T>(self) -> T where L: Trait<T>, R: Trait<T> { + match self { + Either::Left(val) => val.get(), + Either::Right(val) => val.get(), + } + } +} + +fn add_generic<A: Add<B>, B>(lhs: A, rhs: B) -> Either< + impl Trait<<A as Add<B>>::Output>, + impl Trait<<A as Add<B>>::Output> +> { + if true { + Either::Left(Holder(lhs + rhs)) + } else { + Either::Right(Holder(lhs + rhs)) + } +} + +fn add_one( + value: u32, +) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> { + //~^ ERROR: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>` + //~| ERROR: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>` + add_generic(value, 1u32) +} + +pub fn main() { + add_one(3).converge(); +} diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr new file mode 100644 index 0000000000000..427d03b679d5f --- /dev/null +++ b/src/test/ui/issues/issue-58344.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>` is not satisfied + --> $DIR/issue-58344.rs:42:13 + | +LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>` + | + = note: the return type of a function must have a statically known size + +error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>` is not satisfied + --> $DIR/issue-58344.rs:42:52 + | +LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>` + | + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs index b45aedb549ecd..afdf76b7b580f 100644 --- a/src/test/ui/macros/issue-54441.rs +++ b/src/test/ui/macros/issue-54441.rs @@ -1,5 +1,3 @@ -#![feature(macros_in_extern)] - macro_rules! m { () => { let //~ ERROR expected diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index b0fafdc3b6326..af0ee3ae8eca3 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,5 +1,5 @@ error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let` - --> $DIR/issue-54441.rs:5:9 + --> $DIR/issue-54441.rs:3:9 | LL | let | ^^^ unexpected token diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs index 34529cdaa64f1..eb2504d4bfdb7 100644 --- a/src/test/ui/macros/macro-first-set.rs +++ b/src/test/ui/macros/macro-first-set.rs @@ -252,12 +252,6 @@ test_path!(::std); test_path!(std::u8,); test_path!(any, super, super::super::self::path, X<Y>::Z<'a, T=U>); -macro_rules! test_meta_block { - ($($m:meta)* $b:block) => {}; -} - -test_meta_block!(windows {}); - macro_rules! test_lifetime { (1. $($l:lifetime)* $($b:block)*) => {}; (2. $($b:block)* $($l:lifetime)*) => {}; diff --git a/src/test/ui/macros/macro-meta-items-modern.rs b/src/test/ui/macros/macro-meta-items-modern.rs new file mode 100644 index 0000000000000..bc6938d4a6c9a --- /dev/null +++ b/src/test/ui/macros/macro-meta-items-modern.rs @@ -0,0 +1,11 @@ +// check-pass + +macro_rules! check { ($meta:meta) => () } + +check!(meta(a b c d)); +check!(meta[a b c d]); +check!(meta { a b c d }); +check!(meta); +check!(meta = 0); + +fn main() {} diff --git a/src/test/ui/macros/macros-in-extern-rpass.rs b/src/test/ui/macros/macros-in-extern-rpass.rs deleted file mode 100644 index 28abef5cf4edc..0000000000000 --- a/src/test/ui/macros/macros-in-extern-rpass.rs +++ /dev/null @@ -1,30 +0,0 @@ -// run-pass -// ignore-wasm32 - -#![feature(decl_macro, macros_in_extern)] - -macro_rules! returns_isize( - ($ident:ident) => ( - fn $ident() -> isize; - ) -); - -macro takes_u32_returns_u32($ident:ident) { - fn $ident (arg: u32) -> u32; -} - -macro_rules! emits_nothing( - () => () -); - -fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 1isize); - assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); -} - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - returns_isize!(rust_get_test_int); - takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - emits_nothing!(); -} diff --git a/src/test/ui/abi/macros/macros-in-extern.rs b/src/test/ui/macros/macros-in-extern.rs similarity index 60% rename from src/test/ui/abi/macros/macros-in-extern.rs rename to src/test/ui/macros/macros-in-extern.rs index bba8b15cdb035..05002ed72c78d 100644 --- a/src/test/ui/abi/macros/macros-in-extern.rs +++ b/src/test/ui/macros/macros-in-extern.rs @@ -1,3 +1,4 @@ +// run-pass // ignore-wasm32 #![feature(decl_macro)] @@ -16,17 +17,29 @@ macro_rules! emits_nothing( () => () ); +macro_rules! emits_multiple( + () => { + fn f1() -> u32; + fn f2() -> u32; + } +); + +mod defs { + #[no_mangle] extern fn f1() -> u32 { 1 } + #[no_mangle] extern fn f2() -> u32 { 2 } +} + fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 0isize); + assert_eq!(unsafe { rust_get_test_int() }, 1); assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); + assert_eq!(unsafe { f1() }, 1); + assert_eq!(unsafe { f2() }, 2); } #[link(name = "rust_test_helpers", kind = "static")] extern { returns_isize!(rust_get_test_int); - //~^ ERROR macro invocations in `extern {}` blocks are experimental takes_u32_returns_u32!(rust_dbg_extern_identity_u32); - //~^ ERROR macro invocations in `extern {}` blocks are experimental emits_nothing!(); - //~^ ERROR macro invocations in `extern {}` blocks are experimental + emits_multiple!(); } diff --git a/src/test/ui/maybe-bounds-where.stderr b/src/test/ui/maybe-bounds-where.stderr index 78524cbabecd7..15cbce46f0a9b 100644 --- a/src/test/ui/maybe-bounds-where.stderr +++ b/src/test/ui/maybe-bounds-where.stderr @@ -34,7 +34,7 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized; | ^ -warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default. Only `?Sized` is supported +warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported --> $DIR/maybe-bounds-where.rs:15:11 | LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized; diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs index 9edfebcd49471..9035e3380b0c5 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.rs +++ b/src/test/ui/mismatched_types/issue-36053-2.rs @@ -7,5 +7,4 @@ fn main() { once::<&str>("str").fuse().filter(|a: &str| true).count(); //~^ ERROR no method named `count` //~| ERROR type mismatch in closure arguments - //~| ERROR type mismatch in closure arguments } diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 89c7b0981158a..72f3220cc1aba 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -16,14 +16,6 @@ LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | | | expected signature of `for<'r> fn(&'r &str) -> _` -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-36053-2.rs:7:32 - | -LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` - | | - | expected signature of `fn(&&str) -> _` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs new file mode 100644 index 0000000000000..181c770096a5f --- /dev/null +++ b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs @@ -0,0 +1,15 @@ +// In this regression test we check that a trailing `|` in an or-pattern just +// before the `if` token of a `match` guard will receive parser recovery with +// an appropriate error message. + +enum E { A, B } + +fn main() { + match E::A { + E::A | + E::B | //~ ERROR a trailing `|` is not allowed in an or-pattern + if true => { + let recovery_witness: bool = 0; //~ ERROR mismatched types + } + } +} diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr new file mode 100644 index 0000000000000..db6670fc5b1e0 --- /dev/null +++ b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr @@ -0,0 +1,20 @@ +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/issue-64879-trailing-before-guard.rs:10:14 + | +LL | E::A | + | ---- while parsing this or-pattern starting here +LL | E::B | + | ^ help: remove the `|` + +error[E0308]: mismatched types + --> $DIR/issue-64879-trailing-before-guard.rs:12:42 + | +LL | let recovery_witness: bool = 0; + | ^ expected bool, found integer + | + = note: expected type `bool` + found type `{integer}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr index c61b5cb208251..c71c760b1e303 100644 --- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -2,37 +2,49 @@ error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:8:15 | LL | 1 | 2 || 3 => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:13:16 | LL | (1 | 2 || 3) => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:18:16 | LL | (1 | 2 || 3,) => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:25:18 | LL | TS(1 | 2 || 3) => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:32:23 | LL | NS { f: 1 | 2 || 3 } => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:37:16 | LL | [1 | 2 || 3] => (), - | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here error: unexpected token `||` after pattern --> $DIR/multiple-pattern-typo.rs:42:9 diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 2a3a6abfb7b62..6d08b47c058ed 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -51,24 +51,32 @@ error: a leading `|` is only allowed in a top-level pattern | LL | let ( || A | B) = E::A; | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/or-patterns-syntactic-fail.rs:48:11 | LL | let [ || A | B ] = [E::A]; | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/or-patterns-syntactic-fail.rs:49:13 | LL | let TS( || A | B ); | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/or-patterns-syntactic-fail.rs:50:17 | LL | let NS { f: || A | B }; | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: no rules expected the token `|` --> $DIR/or-patterns-syntactic-fail.rs:14:15 diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed index e96d76061ac28..443ef398293d9 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.fixed +++ b/src/test/ui/or-patterns/remove-leading-vert.fixed @@ -1,4 +1,4 @@ -// Test the suggestion to remove a leading `|`. +// Test the suggestion to remove a leading, or trailing `|`. // run-rustfix @@ -8,7 +8,7 @@ fn main() {} #[cfg(FALSE)] -fn leading_vert() { +fn leading() { fn fun1( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern fn fun2( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern let ( A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern @@ -21,3 +21,26 @@ fn leading_vert() { let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern } + +#[cfg(FALSE)] +fn trailing() { + let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern + let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern + let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern + let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern + let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern + let ( A | B ): E; //~ ERROR unexpected token `||` after pattern + //~^ ERROR a trailing `|` is not allowed in an or-pattern + match A { + A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern + A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern + A | B => {} //~ ERROR unexpected token `||` after pattern + //~^ ERROR a trailing `|` is not allowed in an or-pattern + | A | B => {} + //~^ ERROR a trailing `|` is not allowed in an or-pattern + } + + let a : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a ; //~ ERROR a trailing `|` is not allowed in an or-pattern +} diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs index 3790b17553fe3..3c427a6f7b23e 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.rs +++ b/src/test/ui/or-patterns/remove-leading-vert.rs @@ -1,4 +1,4 @@ -// Test the suggestion to remove a leading `|`. +// Test the suggestion to remove a leading, or trailing `|`. // run-rustfix @@ -8,7 +8,7 @@ fn main() {} #[cfg(FALSE)] -fn leading_vert() { +fn leading() { fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern @@ -21,3 +21,26 @@ fn leading_vert() { let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern } + +#[cfg(FALSE)] +fn trailing() { + let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern + let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern + let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern + let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern + let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern + let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern + //~^ ERROR a trailing `|` is not allowed in an or-pattern + match A { + A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern + A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern + A || B | => {} //~ ERROR unexpected token `||` after pattern + //~^ ERROR a trailing `|` is not allowed in an or-pattern + | A | B | => {} + //~^ ERROR a trailing `|` is not allowed in an or-pattern + } + + let a | : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a | = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a | ; //~ ERROR a trailing `|` is not allowed in an or-pattern +} diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr index cbe06f997296a..53025230a63c2 100644 --- a/src/test/ui/or-patterns/remove-leading-vert.stderr +++ b/src/test/ui/or-patterns/remove-leading-vert.stderr @@ -9,6 +9,8 @@ error: a leading `|` is not allowed in a parameter pattern | LL | fn fun2( || A: E) {} | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/remove-leading-vert.rs:14:11 @@ -21,6 +23,8 @@ error: a leading `|` is only allowed in a top-level pattern | LL | let ( || A): (E); | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/remove-leading-vert.rs:16:11 @@ -39,6 +43,8 @@ error: a leading `|` is only allowed in a top-level pattern | LL | let [ || A ]: [E; 1]; | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/remove-leading-vert.rs:19:13 @@ -51,6 +57,8 @@ error: a leading `|` is only allowed in a top-level pattern | LL | let TS( || A ): TS; | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` error: a leading `|` is only allowed in a top-level pattern --> $DIR/remove-leading-vert.rs:21:17 @@ -63,6 +71,130 @@ error: a leading `|` is only allowed in a top-level pattern | LL | let NS { f: || A }: NS; | ^^ help: remove the `||` + | + = note: alternatives in or-patterns are separated with `|`, not `||` + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:27:13 + | +LL | let ( A | ): E; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:28:12 + | +LL | let (a |,): (E,); + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:29:17 + | +LL | let ( A | B | ): E; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:30:17 + | +LL | let [ A | B | ]: [E; 1]; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:31:18 + | +LL | let S { f: B | }; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: unexpected token `||` after pattern + --> $DIR/remove-leading-vert.rs:32:13 + | +LL | let ( A || B | ): E; + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:32:18 + | +LL | let ( A || B | ): E; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:35:11 + | +LL | A | => {} + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:36:11 + | +LL | A || => {} + | - ^^ help: remove the `||` + | | + | while parsing this or-pattern starting here + | + = note: alternatives in or-patterns are separated with `|`, not `||` + +error: unexpected token `||` after pattern + --> $DIR/remove-leading-vert.rs:37:11 + | +LL | A || B | => {} + | - ^^ help: use a single `|` to separate multiple alternative patterns: `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:37:16 + | +LL | A || B | => {} + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:39:17 + | +LL | | A | B | => {} + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:43:11 + | +LL | let a | : u8 = 0; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:44:11 + | +LL | let a | = 0; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here + +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/remove-leading-vert.rs:45:11 + | +LL | let a | ; + | - ^ help: remove the `|` + | | + | while parsing this or-pattern starting here -error: aborting due to 11 previous errors +error: aborting due to 26 previous errors diff --git a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs b/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs deleted file mode 100644 index 15fe3804f9b4f..0000000000000 --- a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs +++ /dev/null @@ -1,26 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream { - assert!(_attr.to_string().is_empty()); - input -} - -#[proc_macro_attribute] -pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream { - assert!(_attr.to_string().is_empty()); - assert!(!_input.to_string().is_empty()); - "".parse().unwrap() -} - -#[proc_macro] -pub fn emit_input(input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.rs b/src/test/ui/proc-macro/dollar-crate-issue-62325.rs index b7b152e669213..223c4047cb2b1 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.rs +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.rs @@ -7,8 +7,6 @@ // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)" // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)" -#![feature(proc_macro_hygiene)] - #[macro_use] extern crate test_macros; extern crate dollar_crate_external; diff --git a/src/test/ui/proc-macro/lifetimes.rs b/src/test/ui/proc-macro/lifetimes.rs index d0dd1b4603b16..5605696715e34 100644 --- a/src/test/ui/proc-macro/lifetimes.rs +++ b/src/test/ui/proc-macro/lifetimes.rs @@ -1,7 +1,5 @@ // aux-build:lifetimes.rs -#![feature(proc_macro_hygiene)] - extern crate lifetimes; use lifetimes::*; diff --git a/src/test/ui/proc-macro/lifetimes.stderr b/src/test/ui/proc-macro/lifetimes.stderr index 6e91201405cc6..10acd4304aa23 100644 --- a/src/test/ui/proc-macro/lifetimes.stderr +++ b/src/test/ui/proc-macro/lifetimes.stderr @@ -1,5 +1,5 @@ error: expected type, found `'` - --> $DIR/lifetimes.rs:9:10 + --> $DIR/lifetimes.rs:7:10 | LL | type A = single_quote_alone!(); | ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.rs b/src/test/ui/proc-macro/macros-in-extern-derive.rs new file mode 100644 index 0000000000000..d2751a353bd93 --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-extern-derive.rs @@ -0,0 +1,6 @@ +extern { + #[derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions + fn f(); +} + +fn main() {} diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr new file mode 100644 index 0000000000000..e2afb7d34c149 --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-extern-derive.stderr @@ -0,0 +1,8 @@ +error: `derive` may only be applied to structs, enums and unions + --> $DIR/macros-in-extern-derive.rs:2:5 + | +LL | #[derive(Copy)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/macros-in-extern-rpass.rs b/src/test/ui/proc-macro/macros-in-extern-rpass.rs deleted file mode 100644 index a30a287a1011b..0000000000000 --- a/src/test/ui/proc-macro/macros-in-extern-rpass.rs +++ /dev/null @@ -1,25 +0,0 @@ -// run-pass -// aux-build:test-macros-rpass.rs -// ignore-wasm32 - -#![feature(macros_in_extern)] - -extern crate test_macros_rpass as test_macros; - -use test_macros::{nop_attr, no_output, emit_input}; - -fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 1isize); - assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); -} - -#[link(name = "rust_test_helpers", kind = "static")] -extern { - #[no_output] - fn some_definitely_unknown_symbol_which_should_be_removed(); - - #[nop_attr] - fn rust_get_test_int() -> isize; - - emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); -} diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.rs b/src/test/ui/proc-macro/macros-in-extern.rs similarity index 62% rename from src/test/ui/abi/proc-macro/macros-in-extern.rs rename to src/test/ui/proc-macro/macros-in-extern.rs index 0477b5c48ecc9..e2b1d55aedc28 100644 --- a/src/test/ui/abi/proc-macro/macros-in-extern.rs +++ b/src/test/ui/proc-macro/macros-in-extern.rs @@ -1,3 +1,4 @@ +// run-pass // aux-build:test-macros.rs // ignore-wasm32 @@ -5,20 +6,17 @@ extern crate test_macros; fn main() { - assert_eq!(unsafe { rust_get_test_int() }, 0isize); + assert_eq!(unsafe { rust_get_test_int() }, 1); assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF); } #[link(name = "rust_test_helpers", kind = "static")] extern { #[empty_attr] - //~^ ERROR macro invocations in `extern {}` blocks are experimental fn some_definitely_unknown_symbol_which_should_be_removed(); #[identity_attr] - //~^ ERROR macro invocations in `extern {}` blocks are experimental fn rust_get_test_int() -> isize; identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); - //~^ ERROR macro invocations in `extern {}` blocks are experimental } diff --git a/src/test/ui/proc-macro/macros-in-type.rs b/src/test/ui/proc-macro/macros-in-type.rs new file mode 100644 index 0000000000000..19ed58eceb964 --- /dev/null +++ b/src/test/ui/proc-macro/macros-in-type.rs @@ -0,0 +1,11 @@ +// check-pass +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +const C: identity!(u8) = 10; + +fn main() { + let c: u8 = C; +} diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index 678dc83b753b5..0096a84f14c34 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -50,7 +50,6 @@ fn attrs() { } fn main() { - let _x: identity!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types if let identity!(Some(_x)) = Some(3) {} //~^ ERROR: procedural macros cannot be expanded to patterns diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index 8462b564ec1d7..14a4f8c0fbca2 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -94,17 +94,8 @@ LL | let _x = #[identity_attr] println!(); = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to types - --> $DIR/proc-macro-gates.rs:53:13 - | -LL | let _x: identity!(u32) = 3; - | ^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/54727 - = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable - error[E0658]: procedural macros cannot be expanded to patterns - --> $DIR/proc-macro-gates.rs:54:12 + --> $DIR/proc-macro-gates.rs:53:12 | LL | if let identity!(Some(_x)) = Some(3) {} | ^^^^^^^^^^^^^^^^^^^ @@ -113,7 +104,7 @@ LL | if let identity!(Some(_x)) = Some(3) {} = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to statements - --> $DIR/proc-macro-gates.rs:57:5 + --> $DIR/proc-macro-gates.rs:56:5 | LL | empty!(struct S;); | ^^^^^^^^^^^^^^^^^^ @@ -122,7 +113,7 @@ LL | empty!(struct S;); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to statements - --> $DIR/proc-macro-gates.rs:58:5 + --> $DIR/proc-macro-gates.rs:57:5 | LL | empty!(let _x = 3;); | ^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +122,7 @@ LL | empty!(let _x = 3;); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to expressions - --> $DIR/proc-macro-gates.rs:60:14 + --> $DIR/proc-macro-gates.rs:59:14 | LL | let _x = identity!(3); | ^^^^^^^^^^^^ @@ -140,7 +131,7 @@ LL | let _x = identity!(3); = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable error[E0658]: procedural macros cannot be expanded to expressions - --> $DIR/proc-macro-gates.rs:61:15 + --> $DIR/proc-macro-gates.rs:60:15 | LL | let _x = [empty!(3)]; | ^^^^^^^^^ @@ -148,6 +139,6 @@ LL | let _x = [empty!(3)]; = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr index 19f758fd8da77..4b1898345a32e 100644 --- a/src/test/ui/rust-2018/trait-import-suggestions.stderr +++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr @@ -5,7 +5,7 @@ LL | x.foobar(); | ^^^^^^ method not found in `u32` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use crate::foo::foobar::Foobar;` error[E0599]: no method named `bar` found for type `u32` in the current scope @@ -15,7 +15,7 @@ LL | x.bar(); | ^^^ method not found in `u32` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use crate::foo::Bar; | @@ -33,7 +33,7 @@ LL | let y = u32::from_str("33"); | ^^^^^^^^ function or associated item not found in `u32` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::str::FromStr; | diff --git a/src/test/ui/shadowed/shadowed-trait-methods.stderr b/src/test/ui/shadowed/shadowed-trait-methods.stderr index 190159ec7b88d..3597cc53420aa 100644 --- a/src/test/ui/shadowed/shadowed-trait-methods.stderr +++ b/src/test/ui/shadowed/shadowed-trait-methods.stderr @@ -5,7 +5,7 @@ LL | ().f() | ^ method not found in `()` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use foo::T; | diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index 39cc66d275c24..64a92c6b0b478 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -28,7 +28,7 @@ LL | S.b(); | ^ method not found in `S` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use method::B; | @@ -62,7 +62,7 @@ LL | S::b(&S); | ^ function or associated item not found in `S` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use method::B; | @@ -96,7 +96,7 @@ LL | S::B; | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use assoc_const::B; | diff --git a/src/test/ui/traits/trait-method-private.stderr b/src/test/ui/traits/trait-method-private.stderr index c1dd9387ebc48..10552acb348be 100644 --- a/src/test/ui/traits/trait-method-private.stderr +++ b/src/test/ui/traits/trait-method-private.stderr @@ -5,7 +5,7 @@ LL | foo.method(); | ^^^^^^ | = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope, perhaps add a `use` for it: +help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use inner::Bar; | diff --git a/src/test/ui/underscore-imports/shadow.stderr b/src/test/ui/underscore-imports/shadow.stderr index 63262d0dc326d..102c17f6f5618 100644 --- a/src/test/ui/underscore-imports/shadow.stderr +++ b/src/test/ui/underscore-imports/shadow.stderr @@ -5,7 +5,7 @@ LL | x.deref(); | ^^^^^ method not found in `&()` | = help: items from traits can only be used if the trait is in scope - = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + = note: the following trait is implemented but not in scope; perhaps add a `use` for it: `use std::ops::Deref;` error: aborting due to previous error