Commit dfb6682089

Andrew Kelley <superjoe30@gmail.com>
2015-12-01 10:29:21
add test for bad import
1 parent 58e375d
example/multiple_files/main.zig
@@ -1,4 +1,4 @@
-export executable "test";
+export executable "test-multiple-files";
 
 use "libc.zig";
 use "foo.zig";
src/analyze.cpp
@@ -11,7 +11,7 @@
 #include "zig_llvm.hpp"
 #include "os.hpp"
 
-static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
+void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
     ErrorMsg *err = allocate<ErrorMsg>(1);
     err->line_start = node->line;
     err->column_start = node->column;
src/analyze.hpp
@@ -9,7 +9,10 @@
 #define ZIG_ANALYZE_HPP
 
 struct CodeGen;
+struct AstNode;
+struct Buf;
 
 void semantic_analyze(CodeGen *g);
+void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
 
 #endif
src/codegen.cpp
@@ -669,6 +669,7 @@ static void init(CodeGen *g, Buf *source_path) {
 }
 
 static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
+    int err;
     Buf full_path = BUF_INIT;
     os_path_join(g->root_source_dir, source_path, &full_path);
 
@@ -736,7 +737,11 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *sou
             Buf full_path = BUF_INIT;
             os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
             Buf *import_code = buf_alloc();
-            os_fetch_file_path(&full_path, import_code);
+            if ((err = os_fetch_file_path(&full_path, import_code))) {
+                add_node_error(g, top_level_decl,
+                        buf_sprintf("unable to open \"%s\": %s", buf_ptr(&full_path), err_str(err)));
+                break;
+            }
             codegen_add_code(g, &top_level_decl->data.use.path, import_code);
         }
     }
src/error.cpp
@@ -6,6 +6,12 @@ const char *err_str(int err) {
         case ErrorNoMem: return "out of memory";
         case ErrorInvalidFormat: return "invalid format";
         case ErrorSemanticAnalyzeFail: return "semantic analyze failed";
+        case ErrorAccess: return "access denied";
+        case ErrorInterrupted: return "interrupted";
+        case ErrorSystemResources: return "lack of system resources";
+        case ErrorFileNotFound: return "file not found";
+        case ErrorFileSystem: return "file system error";
+        case ErrorFileTooBig: return "file too big";
     }
     return "(invalid error)";
 }
src/error.hpp
@@ -13,6 +13,12 @@ enum Error {
     ErrorNoMem,
     ErrorInvalidFormat,
     ErrorSemanticAnalyzeFail,
+    ErrorAccess,
+    ErrorInterrupted,
+    ErrorSystemResources,
+    ErrorFileNotFound,
+    ErrorFileSystem,
+    ErrorFileTooBig,
 };
 
 const char *err_str(int err);
src/os.cpp
@@ -7,6 +7,7 @@
 
 #include "os.hpp"
 #include "util.hpp"
+#include "error.hpp"
 
 #include <unistd.h>
 #include <errno.h>
@@ -143,26 +144,65 @@ void os_write_file(Buf *full_path, Buf *contents) {
 int os_fetch_file(FILE *f, Buf *out_contents) {
     int fd = fileno(f);
     struct stat st;
-    if (fstat(fd, &st))
-        zig_panic("unable to stat file: %s", strerror(errno));
+    if (fstat(fd, &st)) {
+        switch (errno) {
+            case EACCES:
+                return ErrorAccess;
+            case ENOENT:
+                return ErrorFileNotFound;
+            case ENOMEM:
+                return ErrorSystemResources;
+            case EINTR:
+                return ErrorInterrupted;
+            case EINVAL:
+                zig_unreachable();
+            default:
+                return ErrorFileSystem;
+        }
+    }
     off_t big_size = st.st_size;
-    if (big_size > INT_MAX)
-        zig_panic("file too big");
+    if (big_size > INT_MAX) {
+        return ErrorFileTooBig;
+    }
     int size = (int)big_size;
 
     buf_resize(out_contents, size);
     ssize_t ret = read(fd, buf_ptr(out_contents), size);
 
-    if (ret != size)
-        zig_panic("unable to read file: %s", strerror(errno));
+    if (ret != size) {
+        switch (errno) {
+            case EINTR:
+                return ErrorInterrupted;
+            case EINVAL:
+            case EISDIR:
+                zig_unreachable();
+            default:
+                return ErrorFileSystem;
+        }
+    }
 
     return 0;
 }
 
 int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
     FILE *f = fopen(buf_ptr(full_path), "rb");
-    if (!f)
-        zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno));
+    if (!f) {
+        switch (errno) {
+            case EACCES:
+                return ErrorAccess;
+            case EINTR:
+                return ErrorInterrupted;
+            case EINVAL:
+                zig_unreachable();
+            case ENFILE:
+            case ENOMEM:
+                return ErrorSystemResources;
+            case ENOENT:
+                return ErrorFileNotFound;
+            default:
+                return ErrorFileSystem;
+        }
+    }
     int result = os_fetch_file(f, out_contents);
     fclose(f);
     return result;
src/util.hpp
@@ -16,8 +16,6 @@
 
 #define BREAKPOINT __asm("int $0x03")
 
-static const int COMPILE_FAILED_ERR_CODE = 10; // chosen with a random number generator
-
 void zig_panic(const char *format, ...)
     __attribute__((cold))
     __attribute__ ((noreturn))
test/run_tests.cpp
@@ -249,6 +249,10 @@ fn b() {}
 #version("aoeu")
 export executable "test";
     )SOURCE", 1, ".tmp_source.zig:2:1: error: invalid version string");
+
+    add_compile_fail_case("bad import", R"SOURCE(
+use "bogus-does-not-exist.zig";
+    )SOURCE", 1, ".tmp_source.zig:2:1: error: unable to open \"./bogus-does-not-exist.zig\": file not found");
 }
 
 static void print_compiler_invokation(TestCase *test_case, Buf *zig_stderr) {