From 91a528d43e90373ea75bfddb9fd6c15af175d863 Mon Sep 17 00:00:00 2001
From: bing <bingcicle@proton.me>
Date: Sat, 30 Sep 2023 13:50:16 +0800
Subject: [PATCH 1/3] feat: implement `__has_declspec_attribute`

---
 src/Attribute.zig     |  3 ++-
 src/Preprocessor.zig  |  8 ++++++++
 src/Tokenizer.zig     |  3 +++
 src/target.zig        |  1 +
 test/cases/declspec.c | 14 ++++++--------
 5 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/Attribute.zig b/src/Attribute.zig
index fc2a994c..8a3008c1 100644
--- a/src/Attribute.zig
+++ b/src/Attribute.zig
@@ -977,10 +977,11 @@ fn fromStringC2X(namespace: ?[]const u8, name: []const u8) ?Tag {
 }
 
 fn fromStringDeclspec(name: []const u8) ?Tag {
+    const normalized = normalize(name);
     const decls = @typeInfo(attributes).Struct.decls;
     inline for (decls, 0..) |decl, i| {
         if (@hasDecl(@field(attributes, decl.name), "declspec")) {
-            if (mem.eql(u8, @field(attributes, decl.name).declspec, name)) {
+            if (mem.eql(u8, @field(attributes, decl.name).declspec, normalized)) {
                 return @enumFromInt(i);
             }
         }
diff --git a/src/Preprocessor.zig b/src/Preprocessor.zig
index 95758ae3..1bb9ab37 100644
--- a/src/Preprocessor.zig
+++ b/src/Preprocessor.zig
@@ -111,6 +111,10 @@ const builtin_macros = struct {
         .id = .macro_param_has_attribute,
         .source = .generated,
     }};
+    const has_declspec_attribute = [1]RawToken{.{
+        .id = .macro_param_has_declspec_attribute,
+        .source = .generated,
+    }};
     const has_warning = [1]RawToken{.{
         .id = .macro_param_has_warning,
         .source = .generated,
@@ -173,6 +177,7 @@ fn addBuiltinMacro(pp: *Preprocessor, name: []const u8, is_func: bool, tokens: [
 
 pub fn addBuiltinMacros(pp: *Preprocessor) !void {
     try pp.addBuiltinMacro("__has_attribute", true, &builtin_macros.has_attribute);
+    try pp.addBuiltinMacro("__has_declspec_attribute", true, &builtin_macros.has_declspec_attribute);
     try pp.addBuiltinMacro("__has_warning", true, &builtin_macros.has_warning);
     try pp.addBuiltinMacro("__has_feature", true, &builtin_macros.has_feature);
     try pp.addBuiltinMacro("__has_extension", true, &builtin_macros.has_extension);
@@ -1212,6 +1217,7 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token) !?[]co
 fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []const Token, src_loc: Source.Location) Error!bool {
     switch (builtin) {
         .macro_param_has_attribute,
+        .macro_param_has_declspec_attribute,
         .macro_param_has_feature,
         .macro_param_has_extension,
         .macro_param_has_builtin,
@@ -1238,6 +1244,7 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
             const ident_str = pp.expandedSlice(identifier.?);
             return switch (builtin) {
                 .macro_param_has_attribute => Attribute.fromString(.gnu, null, ident_str) != null,
+                .macro_param_has_declspec_attribute => Attribute.fromString(.declspec, null, ident_str) != null,
                 .macro_param_has_feature => features.hasFeature(pp.comp, ident_str),
                 .macro_param_has_extension => features.hasExtension(pp.comp, ident_str),
                 .macro_param_has_builtin => pp.comp.hasBuiltin(ident_str),
@@ -1396,6 +1403,7 @@ fn expandFuncMacro(
                 try buf.append(try pp.makeGeneratedToken(start, .string_literal, tokFromRaw(raw)));
             },
             .macro_param_has_attribute,
+            .macro_param_has_declspec_attribute,
             .macro_param_has_warning,
             .macro_param_has_feature,
             .macro_param_has_extension,
diff --git a/src/Tokenizer.zig b/src/Tokenizer.zig
index 28de3c2c..970f6bf8 100644
--- a/src/Tokenizer.zig
+++ b/src/Tokenizer.zig
@@ -108,6 +108,8 @@ pub const Token = struct {
         macro_ws,
         /// Special token for implementing __has_attribute
         macro_param_has_attribute,
+        /// Special token for implementing __has_declspec_attribute
+        macro_param_has_declspec_attribute,
         /// Special token for implementing __has_warning
         macro_param_has_warning,
         /// Special token for implementing __has_feature
@@ -487,6 +489,7 @@ pub const Token = struct {
                 .stringify_param,
                 .stringify_va_args,
                 .macro_param_has_attribute,
+                .macro_param_has_declspec_attribute,
                 .macro_param_has_warning,
                 .macro_param_has_feature,
                 .macro_param_has_extension,
diff --git a/src/target.zig b/src/target.zig
index d3612a77..4512ce9a 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -684,6 +684,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
         .watchos => "watchos",
         .driverkit => "driverkit",
         .shadermodel => "shadermodel",
+        .liteos => "liteos",
         .opencl,
         .glsl450,
         .vulkan,
diff --git a/test/cases/declspec.c b/test/cases/declspec.c
index 71a6c8d3..9e1a08a9 100644
--- a/test/cases/declspec.c
+++ b/test/cases/declspec.c
@@ -8,21 +8,19 @@ __declspec(aligned(16)) int baz;
 
 _Static_assert(_Alignof(bar) == 16, "wrong alignment");
 
-// #if __has_declspec_attribute(foo)
-// #error fail
-// #endif
+#if __has_declspec_attribute(foo)
+#error fail
+#endif
 
-// #if !__has_declspec_attribute(align)
-// #error fail
-// #endif
+#if !__has_declspec_attribute(align)
+#error fail
+#endif
 
 typedef int Int1 __declspec(align(8));
 typedef __declspec(align(8)) int Int2;
 
 _Static_assert(_Alignof(Int2) == 8, "");
 
-#define TESTS_SKIPPED 2
-
 #define EXPECTED_ERRORS "declspec.c:7:12: warning: __declspec attribute 'aligned' is not supported [-Wignored-attributes]" \
 	"declspec.c:19:18: error: 'declspec' attribute not allowed after declarator" \
 	"declspec.c:19:13: note: this declarator"

From 74d7a2f318bafcccd2e590d971df6dafcbcdcbc5 Mon Sep 17 00:00:00 2001
From: bing <bingcicle@proton.me>
Date: Sat, 30 Sep 2023 20:35:25 +0800
Subject: [PATCH 2/3] __has_declspec_attribute always 0 if not enabled in opts

---
 src/Preprocessor.zig | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/Preprocessor.zig b/src/Preprocessor.zig
index 1bb9ab37..c8648aaa 100644
--- a/src/Preprocessor.zig
+++ b/src/Preprocessor.zig
@@ -1244,7 +1244,12 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
             const ident_str = pp.expandedSlice(identifier.?);
             return switch (builtin) {
                 .macro_param_has_attribute => Attribute.fromString(.gnu, null, ident_str) != null,
-                .macro_param_has_declspec_attribute => Attribute.fromString(.declspec, null, ident_str) != null,
+                .macro_param_has_declspec_attribute => {
+                    return if (pp.comp.langopts.declspec_attrs)
+                        Attribute.fromString(.declspec, null, ident_str) != null
+                    else
+                        false;
+                },
                 .macro_param_has_feature => features.hasFeature(pp.comp, ident_str),
                 .macro_param_has_extension => features.hasExtension(pp.comp, ident_str),
                 .macro_param_has_builtin => pp.comp.hasBuiltin(ident_str),

From 5ae950cecb8162f7c52680125902754aeb400bc7 Mon Sep 17 00:00:00 2001
From: bing <bingcicle@proton.me>
Date: Sat, 30 Sep 2023 20:35:34 +0800
Subject: [PATCH 3/3] add no declspec tests

---
 test/cases/no declspec.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/test/cases/no declspec.c b/test/cases/no declspec.c
index 0b4c36d0..720a2c66 100644
--- a/test/cases/no declspec.c	
+++ b/test/cases/no declspec.c	
@@ -1,4 +1,12 @@
 __declspec(align(4)) int foo;
 
+#if __has_declspec_attribute(noreturn)
+#error "__has_declspec_attribute macro should not work without -fdeclspec"
+#endif
+
+#if __has_declspec_attribute(x)
+#error "__has_declspec_attribute macro should not work without -fdeclspec"
+#endif
+
 #define EXPECTED_ERRORS \
     "no declspec.c:1:1: error: '__declspec' attributes are not enabled; use '-fdeclspec' or '-fms-extensions' to enable support for __declspec attributes" \