Commit 71573584cd

Andrew Kelley <andrew@ziglang.org>
2020-02-21 19:34:55
std.Target.parse gives parsing diagnostics
1 parent 7da7fbb
Changed files (2)
lib
src-self-hosted
lib/std/target.zig
@@ -727,18 +727,47 @@ pub const Target = union(enum) {
         /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
         /// to remove from the set.
         cpu_features: []const u8 = "baseline",
+
+        /// If this is provided, the function will populate some information about parsing failures,
+        /// so that user-friendly error messages can be delivered.
+        diagnostics: ?*Diagnostics = null,
+
+        pub const Diagnostics = struct {
+            /// If the architecture was determined, this will be populated.
+            arch: ?Cpu.Arch = null,
+
+            /// If the OS was determined, this will be populated.
+            os: ?Os = null,
+
+            /// If the ABI was determined, this will be populated.
+            abi: ?Abi = null,
+
+            /// If the CPU name was determined, this will be populated.
+            cpu_name: ?[]const u8 = null,
+
+            /// If error.UnknownCpuFeature is returned, this will be populated.
+            unknown_feature_name: ?[]const u8 = null,
+        };
     };
 
     pub fn parse(args: ParseOptions) !Target {
+        var dummy_diags: ParseOptions.Diagnostics = undefined;
+        var diags = args.diagnostics orelse &dummy_diags;
+
         var it = mem.separate(args.arch_os_abi, "-");
         const arch_name = it.next() orelse return error.MissingArchitecture;
-        const os_name = it.next() orelse return error.MissingOperatingSystem;
-        const abi_name = it.next();
-        if (it.next() != null) return error.UnexpectedExtraField;
-
         const arch = try Cpu.Arch.parse(arch_name);
+        diags.arch = arch;
+
+        const os_name = it.next() orelse return error.MissingOperatingSystem;
         const os = try Os.parse(os_name);
+        diags.os = os;
+
+        const abi_name = it.next();
         const abi = if (abi_name) |n| try Abi.parse(n) else Abi.default(arch, os);
+        diags.abi = abi;
+
+        if (it.next() != null) return error.UnexpectedExtraField;
 
         const all_features = arch.allFeaturesList();
         var index: usize = 0;
@@ -749,6 +778,8 @@ pub const Target = union(enum) {
             index += 1;
         }
         const cpu_name = args.cpu_features[0..index];
+        diags.cpu_name = cpu_name;
+
         const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: {
             const cpu_model = try arch.parseCpuModel(cpu_name);
 
@@ -775,6 +806,7 @@ pub const Target = union(enum) {
                         break;
                     }
                 } else {
+                    diags.unknown_feature_name = feature_name;
                     return error.UnknownCpuFeature;
                 }
             }
src-self-hosted/stage2.zig
@@ -661,9 +661,7 @@ export fn stage2_target_parse(
         error.MissingOperatingSystem => return .MissingOperatingSystem,
         error.MissingArchitecture => return .MissingArchitecture,
         error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
-        error.UnknownCpu => return .UnknownCpu,
         error.UnexpectedExtraField => return .SemanticAnalyzeFail,
-        error.UnknownCpuFeature => return .UnknownCpuFeature,
     };
     return .None;
 }
@@ -676,7 +674,38 @@ fn stage2TargetParse(
     const target: Target = if (zig_triple_oz) |zig_triple_z| blk: {
         const zig_triple = mem.toSliceConst(u8, zig_triple_z);
         const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";
-        break :blk try Target.parse(.{ .arch_os_abi = zig_triple, .cpu_features = mcpu });
+        var diags: std.Target.ParseOptions.Diagnostics = .{};
+        break :blk Target.parse(.{
+            .arch_os_abi = zig_triple,
+            .cpu_features = mcpu,
+            .diagnostics = &diags,
+        }) catch |err| switch (err) {
+            error.UnknownCpu => {
+                std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
+                    diags.cpu_name.?,
+                    @tagName(diags.arch.?),
+                });
+                for (diags.arch.?.allCpuModels()) |cpu| {
+                    std.debug.warn(" {}\n", .{cpu.name});
+                }
+                process.exit(1);
+            },
+            error.UnknownCpuFeature => {
+                std.debug.warn(
+                    \\Unknown CPU feature: '{}'
+                    \\Available CPU features for architecture '{}':
+                    \\
+                , .{
+                    diags.unknown_feature_name,
+                    @tagName(diags.arch.?),
+                });
+                for (diags.arch.?.allFeaturesList()) |feature| {
+                    std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
+                }
+                process.exit(1);
+            },
+            else => |e| return e,
+        };
     } else Target.Native;
 
     try stage1_target.fromTarget(target);