Commit 40480c7cdc

Andrew Kelley <superjoe30@gmail.com>
2017-11-25 01:26:05
translate-c supports string literals
1 parent 68312af
Changed files (2)
src/translate_c.cpp
@@ -324,6 +324,10 @@ static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) {
     return node;
 }
 
+static Buf *string_ref_to_buf(StringRef string_ref) {
+    return buf_create_from_mem((const char *)string_ref.bytes_begin(), string_ref.size());
+}
+
 static const char *decl_name(const Decl *decl) {
     const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl);
     return (const char *)named_decl->getName().bytes_begin();
@@ -339,6 +343,44 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int)
 
 static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
 
+static QualType get_expr_qual_type(Context *c, const Expr *expr) {
+    // String literals in C are `char *` but they should really be `const char *`.
+    if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
+        const ImplicitCastExpr *cast_expr = static_cast<const ImplicitCastExpr *>(expr);
+        if (cast_expr->getCastKind() == CK_ArrayToPointerDecay) {
+            const Expr *sub_expr = cast_expr->getSubExpr();
+            if (sub_expr->getStmtClass() == Stmt::StringLiteralClass) {
+                QualType array_qt = sub_expr->getType();
+                const ArrayType *array_type = static_cast<const ArrayType *>(array_qt.getTypePtr());
+                QualType pointee_qt = array_type->getElementType();
+                pointee_qt.addConst();
+                return c->ctx->getPointerType(pointee_qt);
+            }
+        }
+    }
+    return expr->getType();
+}
+
+static AstNode *get_expr_type(Context *c, const Expr *expr) {
+    return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart());
+}
+
+static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) {
+    QualType t1 = get_expr_qual_type(c, expr1);
+    QualType t2 = get_expr_qual_type(c, expr2);
+
+    if (t1.isConstQualified() != t2.isConstQualified()) {
+        return false;
+    }
+    if (t1.isVolatileQualified() != t2.isVolatileQualified()) {
+        return false;
+    }
+    if (t1.isRestrictQualified() != t2.isRestrictQualified()) {
+        return false;
+    }
+    return t1.getTypePtr() == t2.getTypePtr();
+}
+
 static bool is_c_void_type(AstNode *node) {
     return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
 }
@@ -1335,7 +1377,11 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas
                 if (target_node == nullptr)
                     return nullptr;
 
-                AstNode *dest_type_node = trans_qual_type(c, stmt->getType(), stmt->getLocStart());
+                if (expr_types_equal(c, stmt, stmt->getSubExpr())) {
+                    return target_node;
+                }
+
+                AstNode *dest_type_node = get_expr_type(c, stmt);
 
                 AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
                 node->data.fn_call_expr.params.append(dest_type_node);
@@ -2126,6 +2172,24 @@ static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) {
     return while_node;
 }
 
+static AstNode *trans_string_literal(Context *c, AstNode *block, StringLiteral *stmt) {
+    switch (stmt->getKind()) {
+        case StringLiteral::Ascii:
+        case StringLiteral::UTF8:
+            return trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString()));
+        case StringLiteral::UTF16:
+            emit_warning(c, stmt->getLocStart(), "TODO support UTF16 string literals");
+            return nullptr;
+        case StringLiteral::UTF32:
+            emit_warning(c, stmt->getLocStart(), "TODO support UTF32 string literals");
+            return nullptr;
+        case StringLiteral::Wide:
+            emit_warning(c, stmt->getLocStart(), "TODO support wide string literals");
+            return nullptr;
+    }
+    zig_unreachable();
+}
+
 static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) {
     Stmt::StmtClass sc = stmt->getStmtClass();
     switch (sc) {
@@ -2167,6 +2231,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s
             return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt);
         case Stmt::DoStmtClass:
             return trans_do_loop(c, block, (DoStmt *)stmt);
+        case Stmt::StringLiteralClass:
+            return trans_string_literal(c, block, (StringLiteral *)stmt);
         case Stmt::CaseStmtClass:
             emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");
             return nullptr;
@@ -2488,9 +2554,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s
         case Stmt::StmtExprClass:
             emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass");
             return nullptr;
-        case Stmt::StringLiteralClass:
-            emit_warning(c, stmt->getLocStart(), "TODO handle C StringLiteralClass");
-            return nullptr;
         case Stmt::SubstNonTypeTemplateParmExprClass:
             emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass");
             return nullptr;
@@ -3530,7 +3593,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
                     break;
             }
             StringRef msg_str_ref = it->getMessage();
-            Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin());
+            Buf *msg = string_ref_to_buf(msg_str_ref);
             FullSourceLoc fsl = it->getLocation();
             if (fsl.hasManager()) {
                 FileID file_id = fsl.getFileID();
@@ -3543,7 +3606,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
                 if (filename.empty()) {
                     path = buf_alloc();
                 } else {
-                    path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size());
+                    path = string_ref_to_buf(filename);
                 }
 
                 ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
test/translate_c.zig
@@ -929,6 +929,16 @@ pub fn addCases(cases: &tests.TranslateCContext) {
         \\    return *(??ptr);
         \\}
     );
+
+    cases.add("string literal",
+        \\const char *foo(void) {
+        \\    return "bar";
+        \\}
+    ,
+        \\pub fn foo() -> ?&const u8 {
+        \\    return c"bar";
+        \\}
+    );
 }