Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gcc/rust/ast/rust-ast-collector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,9 @@ TokenCollector::visit (Token &tok)
case RAW_STRING_LITERAL:
push (Rust::Token::make_raw_string (tok.get_locus (), std::move (data)));
break;
case C_STRING_LITERAL:
push (Rust::Token::make_c_string (tok.get_locus (), std::move (data)));
break;
case INNER_DOC_COMMENT:
push (Rust::Token::make_inner_doc_comment (tok.get_locus (),
std::move (data)));
Expand Down Expand Up @@ -863,6 +866,9 @@ TokenCollector::visit (Literal &lit, location_t locus)
case Literal::LitType::RAW_STRING:
push (Rust::Token::make_raw_string (locus, std::move (value)));
break;
case Literal::LitType::C_STRING:
push (Rust::Token::make_c_string (locus, std::move (value)));
break;
case Literal::LitType::INT:
{
auto val_len = value.length ();
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/ast/rust-ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3620,6 +3620,7 @@ AttributeParser::parse_meta_item_inner ()
case BYTE_CHAR_LITERAL:
case BYTE_STRING_LITERAL:
case RAW_STRING_LITERAL:
case C_STRING_LITERAL:
case INT_LITERAL:
case FLOAT_LITERAL:
case TRUE_LITERAL:
Expand Down
2 changes: 2 additions & 0 deletions gcc/rust/ast/rust-ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ class Token : public TokenTree, public MacroMatch
case STRING_LITERAL:
case BYTE_STRING_LITERAL:
case RAW_STRING_LITERAL:
case C_STRING_LITERAL:
return true;
default:
return false;
Expand Down Expand Up @@ -272,6 +273,7 @@ struct Literal
BYTE,
BYTE_STRING,
RAW_STRING,
C_STRING,
INT,
FLOAT,
BOOL,
Expand Down
48 changes: 46 additions & 2 deletions gcc/rust/backend/rust-compile-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,23 @@ CompileExpr::visit (HIR::FieldAccessExpr &expr)
nullptr, &field_index);
rust_assert (ok);

tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
receiver_ref = indirect;
// TODO this check is only used for CStr, test again when we support
// compilation of #[repr(transparent)] structs
if (RS_DST_FLAG_P (TREE_TYPE (receiver_ref)))
{
const TyTy::StructFieldType *field
= variant->get_field_at_index (field_index);
tree field_type
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
translated = fold_build1_loc (expr.get_locus (), VIEW_CONVERT_EXPR,
field_type, receiver_ref);
return;
}
else
{
tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
receiver_ref = indirect;
}
}

translated = Backend::struct_field_expression (receiver_ref, field_index,
Expand Down Expand Up @@ -1089,6 +1104,10 @@ CompileExpr::visit (HIR::LiteralExpr &expr)
case HIR::Literal::BYTE_STRING:
translated = compile_byte_string_literal (expr, tyty);
return;

case HIR::Literal::C_STRING:
translated = compile_c_string_literal (expr, tyty);
return;
}
}

Expand Down Expand Up @@ -1902,6 +1921,31 @@ CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr,
return address_expression (constructed, expr.get_locus ());
}

tree
CompileExpr::compile_c_string_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty)
{
// Copied from compile_string_literal
tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty);

rust_assert (expr.get_lit_type () == HIR::Literal::C_STRING);
const auto literal_value = expr.get_literal ();

auto base = Backend::string_constant_expression (literal_value.as_string ());
tree data = address_expression (base, expr.get_locus ());

TyTy::BaseType *usize = nullptr;
bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
rust_assert (ok);
tree type = TyTyResolveCompile::compile (ctx, usize);

// +1 for null terminator, unlike Rust string literals.
tree size = build_int_cstu (type, literal_value.as_string ().size () + 1);
Comment on lines +1942 to +1943

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct, but don't we also need to add an extra zero byte at the end?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it taken care of by the backend already?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++11 strings already come with a null terminator, so I don't think we need to handle it.


return Backend::constructor_expression (fat_pointer, false, {data, size}, -1,
expr.get_locus ());
}
Comment thread
Polygonalr marked this conversation as resolved.

tree
CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
location_t location)
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/backend/rust-compile-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor
tree compile_byte_string_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);

tree compile_c_string_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty);

tree type_cast_expression (tree type_to_cast_to, tree expr, location_t locus);

tree array_value_expr (location_t expr_locus,
Expand Down
23 changes: 23 additions & 0 deletions gcc/rust/backend/rust-compile-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
const TyTy::SliceType *slice = nullptr;
const TyTy::StrType *str = nullptr;
const TyTy::DynamicObjectType *dyn = nullptr;
const TyTy::ADTType *adt = nullptr;
if (type.is_dyn_slice_type (&slice))
{
tree type_record = create_slice_type_record (*slice);
Expand Down Expand Up @@ -684,6 +685,28 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)

return;
}
// Check for CStr, create a specific record for it
else if (type.is_dyn_cstr_type (&adt))
{
// CStr in core crate is defined as the following:
//
// #[repr(transparent)]
// pub struct CStr {
// inner: [u8]
// }
//
// Reuse the c_char (u8) slice fat-pointer layout
TyTy::BaseType *u8 = nullptr;
ctx->get_tyctx ()->lookup_builtin ("u8", &u8);
// Create a synthetic SliceType over u8 and use that record layout
TyTy::SliceType synthetic_slice (adt->get_ref (), adt->get_ident ().locus,
TyTy::TyVar (u8->get_ref ()));
tree type_record = create_slice_type_record (synthetic_slice);
translated
= Backend::named_type ("&CStr", type_record, adt->get_ident ().locus);

return;
}

tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/hir/rust-ast-lower-base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,9 @@ ASTLoweringBase::lower_literal (const AST::Literal &literal)
case AST::Literal::LitType::RAW_STRING:
type = HIR::Literal::LitType::STRING;
break;
case AST::Literal::LitType::C_STRING:
type = HIR::Literal::LitType::C_STRING;
break;
case AST::Literal::LitType::INT:
type = HIR::Literal::LitType::INT;
break;
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/hir/tree/rust-hir-literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct Literal
STRING,
BYTE,
BYTE_STRING,
C_STRING,
INT,
FLOAT,
BOOL
Expand Down
4 changes: 4 additions & 0 deletions gcc/rust/lang.opt
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,8 @@ frust-unused-check-2.0
Rust Var(flag_unused_check_2_0)
Use the new unused variable check implementation.

frust-c-style-string-literals
Rust Var(flag_c_style_string_literals)
Enable parsing and compilation of C-styled string literals.

; This comment is to ensure we retain the blank line above.
80 changes: 80 additions & 0 deletions gcc/rust/lex/rust-lex.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,10 @@ Lexer::build_token ()
return parse_raw_byte_string (loc);
}

// C-style strings
else if (current_char == 'c' && peek_input () == '"')
return parse_c_string (loc);
Comment on lines +1066 to +1068

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in a later PR you can also add C-style raw strings the same way, but I don't know if the kernel makes use of those


// raw identifiers and raw strings
if (current_char == 'r')
{
Expand Down Expand Up @@ -1749,6 +1753,82 @@ Lexer::parse_byte_string (location_t loc)
return Token::make_byte_string (loc, std::move (str));
}

// Parses a C-style string.
TokenPtr
Lexer::parse_c_string (location_t loc)
{
skip_input ();
current_column++;

// Mostly same code copied from parse_string...

std::string str;
str.reserve (16); // some sensible default

current_char = peek_input ();

const location_t string_begin_locus = get_current_location ();

while (current_char.value != '"' && !current_char.is_eof ())
{
if (current_char.value == '\\')
{
int length = 1;

auto escape_pair = parse_escape ('"');
current_char = std::get<0> (escape_pair);

if (current_char == Codepoint (0) && std::get<2> (escape_pair))
length = std::get<1> (escape_pair) - 1;
else
length += std::get<1> (escape_pair);

if (current_char != Codepoint (0) || !std::get<2> (escape_pair))
str += current_char.as_string ();

current_column += length;

// FIXME: parse_escape does not update current_char correctly.
current_char = peek_input ();
continue;
}

current_column++;
if (current_char.value == '\n')
{
current_line++;
current_column = 1;
// tell line_table that new line starts
start_line (current_line, max_column_hint);
}
Comment thread
Polygonalr marked this conversation as resolved.

str += current_char;
skip_input ();
current_char = peek_input ();
}

if (current_char.value == '"')
{
current_column++;

skip_input ();
current_char = peek_input ();
}
else if (current_char.is_eof ())
{
rust_error_at (string_begin_locus, "unended C string literal");
return Token::make (END_OF_FILE, get_current_location ());
}
else
{
rust_unreachable ();
}

str.shrink_to_fit ();

return Token::make_c_string (loc, std::move (str));
}

// Parses a raw byte string.
TokenPtr
Lexer::parse_raw_byte_string (location_t loc)
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/lex/rust-lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class Lexer
TokenPtr parse_string (location_t loc);
TokenPtr maybe_parse_raw_string (location_t loc);
TokenPtr parse_raw_string (location_t loc, int initial_hash_count);
TokenPtr parse_c_string (location_t loc);
TokenPtr parse_non_decimal_int_literals (location_t loc);
TokenPtr parse_decimal_int_or_float (location_t loc);
TokenPtr parse_char_or_lifetime (location_t loc);
Expand Down
8 changes: 8 additions & 0 deletions gcc/rust/lex/rust-token.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ enum PrimitiveCoreType
RS_TOKEN (BYTE_STRING_LITERAL, "byte string literal") \
RS_TOKEN (RAW_STRING_LITERAL, "raw string literal") \
RS_TOKEN (BYTE_CHAR_LITERAL, "byte character literal") \
RS_TOKEN (C_STRING_LITERAL, "C string literal") \
RS_TOKEN (RAW_C_STRING_LITERAL, "raw C string literal") \
RS_TOKEN (LIFETIME, "lifetime") /* TODO: improve token type */ \
/* Have "interpolated" tokens (whatever that means)? identifer, path, type, \
* pattern, */ \
Expand Down Expand Up @@ -422,6 +424,11 @@ class Token
return TokenPtr (new Token (RAW_STRING_LITERAL, locus, std::move (str)));
}

static TokenPtr make_c_string (location_t locus, std::string str)
{
return TokenPtr (new Token (C_STRING_LITERAL, locus, std::move (str)));
}

// Makes and returns a new TokenPtr of type INNER_DOC_COMMENT.
static TokenPtr make_inner_doc_comment (location_t locus, std::string str)
{
Expand Down Expand Up @@ -504,6 +511,7 @@ class Token
case BYTE_CHAR_LITERAL:
case BYTE_STRING_LITERAL:
case RAW_STRING_LITERAL:
case C_STRING_LITERAL:
return true;
default:
return false;
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/parse/rust-parse-impl-attribute.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,9 @@ Parser<ManagedTokenSource>::parse_attr_input ()
case BYTE_STRING_LITERAL:
lit_type = AST::Literal::BYTE_STRING;
break;
case C_STRING_LITERAL:
lit_type = AST::Literal::C_STRING;
break;
case RAW_STRING_LITERAL:
lit_type = AST::Literal::RAW_STRING;
break;
Expand Down
39 changes: 39 additions & 0 deletions gcc/rust/parse/rust-parse-impl-expr.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,28 @@ Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
type = AST::Literal::RAW_STRING;
literal_value = t->get_str ();
lexer.skip_token ();
break;
case C_STRING_LITERAL:
{
if (flag_c_style_string_literals)
{
type = AST::Literal::C_STRING;
literal_value = t->get_str ();
lexer.skip_token ();
}
else
{
add_error (
Error (t->get_locus (),
"unexpected token %qs when parsing literal expression - "
"C-style string literals require "
"%<-frust-c-style-string-literals%> to be enabled",
t->get_token_description ()));
return tl::unexpected<Parse::Error::Node> (
Parse::Error::Node::MALFORMED);
}
}

break;
case INT_LITERAL:
type = AST::Literal::INT;
Expand Down Expand Up @@ -2101,6 +2123,23 @@ Parser<ManagedTokenSource>::null_denotation_not_path (
return std::unique_ptr<AST::LiteralExpr> (
new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING,
tok->get_type_hint (), {}, tok->get_locus ()));
case C_STRING_LITERAL:
if (flag_c_style_string_literals)
{
return std::unique_ptr<AST::LiteralExpr> (
new AST::LiteralExpr (tok->get_str (), AST::Literal::C_STRING,
tok->get_type_hint (), {},
tok->get_locus ()));
}
else
{
Error error (tok->get_locus (),
"C-style string literals require "
"%<-frust-c-style-string-literals%> to be enabled");
add_error (std::move (error));
return tl::unexpected<Parse::Error::Expr> (
Parse::Error::Expr::MALFORMED);
}
case CHAR_LITERAL:
return std::unique_ptr<AST::LiteralExpr> (
new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
Expand Down
1 change: 1 addition & 0 deletions gcc/rust/parse/rust-parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "rust-feature-store.h"

#include "expected.h"
#include "options.h"

namespace Rust {

Expand Down
Loading
Loading