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..c8648aaa 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,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 => { + 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), @@ -1396,6 +1408,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/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" 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" \