Skip to content

Commit 3e73077

Browse files
Chris Wall (WIN SDE)Copilot
andcommitted
Fix clang-cl: move [[deprecated]] to forward declarations
clang-cl rejects [[deprecated]] on redeclarations after a type is already defined (-Werror,-Wignored-attributes). Fix by placing the attribute on forward declarations in .0.h headers instead. Move #pragma warning(push/disable: 4996) to the preamble of main namespace headers so it covers both included impl headers and internal implementation code. The pop comes after internal code, ensuring user code still sees deprecation warnings. Also add escape_cpp_string_literal() for deprecation messages to handle quotes/backslashes/newlines in metadata strings, and remove the now-unused wrap_suppress_deprecation_warnings and write_deprecated_redeclaration functions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ea56ece commit 3e73077

3 files changed

Lines changed: 64 additions & 66 deletions

File tree

cppwinrt/code_writers.h

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,6 @@ namespace cppwinrt
123123
return { w, write_endif };
124124
}
125125

126-
static void write_pragma_warning_pop(writer& w)
127-
{
128-
w.write("#pragma warning(pop)\n");
129-
}
130-
131-
[[nodiscard]] static finish_with wrap_suppress_deprecation_warnings(writer& w)
132-
{
133-
w.write("#pragma warning(push)\n#pragma warning(disable: 4996)\n");
134-
return { w, write_pragma_warning_pop };
135-
}
136-
137126
static void write_parent_depends(writer& w, cache const& c, std::string_view const& type_namespace)
138127
{
139128
auto pos = type_namespace.rfind('.');
@@ -209,10 +198,9 @@ namespace cppwinrt
209198
template <typename T>
210199
static void write_deprecated_impl(writer& w, T const& row)
211200
{
212-
if (auto attr = get_attribute(row, "Windows.Foundation.Metadata", "DeprecatedAttribute"))
201+
if (is_deprecated(row))
213202
{
214-
auto message = get_attribute_value<std::string_view>(attr, 0);
215-
w.write("[[deprecated(\"%\")]] ", message);
203+
w.write("[[deprecated(\"%\")]] ", get_deprecated_message(row));
216204
}
217205
}
218206

@@ -226,20 +214,6 @@ namespace cppwinrt
226214
write_deprecated_impl(w, field);
227215
}
228216

229-
static void write_deprecated_redeclaration(writer& w, TypeDef const& type)
230-
{
231-
if (is_removed(type))
232-
{
233-
return;
234-
}
235-
236-
if (auto attr = get_attribute(type, "Windows.Foundation.Metadata", "DeprecatedAttribute"))
237-
{
238-
auto message = get_attribute_value<std::string_view>(attr, 0);
239-
w.write(" struct [[deprecated(\"%\")]] %;\n", message, type.TypeName());
240-
}
241-
}
242-
243217
static void write_enum_field(writer& w, Field const& field, bool parent_deprecated, std::string_view parent_deprecated_message)
244218
{
245219
if (is_removed(field))
@@ -422,6 +396,12 @@ namespace cppwinrt
422396

423397
if (empty(generics))
424398
{
399+
if (!is_removed(type) && is_deprecated(type))
400+
{
401+
w.write(" struct [[deprecated(\"%\")]] %;\n", get_deprecated_message(type), type_name.name);
402+
return;
403+
}
404+
425405
auto format = R"( struct %;
426406
)";
427407

cppwinrt/file_writers.h

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -181,51 +181,45 @@ namespace cppwinrt
181181
writer w;
182182
w.type_namespace = ns;
183183

184-
// Suppress C4996 (deprecated) in internal projection implementation code.
185-
// The deprecated redeclarations below (outside the suppression) trigger warnings in user code.
184+
// Internal projection implementation code.
185+
// Deprecation warnings (C4996) are suppressed via #pragma warning(push/disable)
186+
// written in the preamble, covering both the included headers and this section.
187+
// The [[deprecated]] attributes on forward declarations in .0.h headers trigger
188+
// warnings only in user code (after the #pragma warning(pop) below).
186189
{
187-
auto wrap_deprecation = wrap_suppress_deprecation_warnings(w);
190+
auto wrap_impl = wrap_impl_namespace(w);
191+
w.write_each<write_consume_definitions>(members.interfaces);
192+
w.param_names = true;
193+
w.write_each<write_delegate_implementation>(members.delegates);
194+
w.write_each<write_produce>(members.interfaces, c);
195+
w.write_each<write_dispatch_overridable>(members.classes);
196+
}
197+
{
198+
auto wrap_type = wrap_type_namespace(w, ns);
199+
w.write_each<write_enum_operators>(members.enums);
200+
w.write_each<write_class_definitions>(members.classes);
201+
w.write_each<write_fast_class_base_definitions>(members.classes);
202+
w.write_each<write_delegate_definition>(members.delegates);
203+
w.write_each<write_interface_override_methods>(members.classes);
204+
w.write_each<write_class_override>(members.classes);
205+
}
206+
{
207+
auto wrap_std = wrap_std_namespace(w);
188208

189209
{
190-
auto wrap_impl = wrap_impl_namespace(w);
191-
w.write_each<write_consume_definitions>(members.interfaces);
192-
w.param_names = true;
193-
w.write_each<write_delegate_implementation>(members.delegates);
194-
w.write_each<write_produce>(members.interfaces, c);
195-
w.write_each<write_dispatch_overridable>(members.classes);
210+
auto wrap_lean = wrap_lean_and_mean(w);
211+
w.write_each<write_std_hash>(members.interfaces);
212+
w.write_each<write_std_hash>(members.classes);
196213
}
197214
{
198-
auto wrap_type = wrap_type_namespace(w, ns);
199-
w.write_each<write_enum_operators>(members.enums);
200-
w.write_each<write_class_definitions>(members.classes);
201-
w.write_each<write_fast_class_base_definitions>(members.classes);
202-
w.write_each<write_delegate_definition>(members.delegates);
203-
w.write_each<write_interface_override_methods>(members.classes);
204-
w.write_each<write_class_override>(members.classes);
205-
}
206-
{
207-
auto wrap_std = wrap_std_namespace(w);
208-
209-
{
210-
auto wrap_lean = wrap_lean_and_mean(w);
211-
w.write_each<write_std_hash>(members.interfaces);
212-
w.write_each<write_std_hash>(members.classes);
213-
}
214-
{
215-
auto wrap_format = wrap_ifdef(w, "__cpp_lib_format");
216-
w.write_each<write_std_formatter>(members.interfaces);
217-
w.write_each<write_std_formatter>(members.classes);
218-
}
215+
auto wrap_format = wrap_ifdef(w, "__cpp_lib_format");
216+
w.write_each<write_std_formatter>(members.interfaces);
217+
w.write_each<write_std_formatter>(members.classes);
219218
}
220219
}
221220

222-
{
223-
auto wrap_type = wrap_type_namespace(w, ns);
224-
w.write_each<write_deprecated_redeclaration>(members.interfaces);
225-
w.write_each<write_deprecated_redeclaration>(members.classes);
226-
w.write_each<write_deprecated_redeclaration>(members.delegates);
227-
w.write_each<write_deprecated_redeclaration>(members.structs);
228-
}
221+
// End deprecation suppression - user code after this gets deprecation warnings.
222+
w.write("#pragma warning(pop)\n");
229223

230224
write_namespace_special(w, ns);
231225

@@ -234,6 +228,11 @@ namespace cppwinrt
234228
write_preamble(w);
235229
write_open_file_guard(w, ns);
236230
write_version_assert(w);
231+
232+
// Suppress C4996 (deprecated) for included headers and internal implementation code.
233+
// The pop is written in the body section above.
234+
w.write("#pragma warning(push)\n#pragma warning(disable: 4996)\n");
235+
237236
write_parent_depends(w, c, ns);
238237

239238
for (auto&& depends : w.depends)

cppwinrt/helpers.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,30 @@ namespace cppwinrt
248248
return has_attribute(row, "Windows.Foundation.Metadata", "DeprecatedAttribute");
249249
}
250250

251+
inline std::string escape_cpp_string_literal(std::string_view input)
252+
{
253+
std::string result;
254+
result.reserve(input.size());
255+
for (char c : input)
256+
{
257+
switch (c)
258+
{
259+
case '\\': result += "\\\\"; break;
260+
case '"': result += "\\\""; break;
261+
case '\n': result += "\\n"; break;
262+
case '\r': result += "\\r"; break;
263+
case '\t': result += "\\t"; break;
264+
default: result += c; break;
265+
}
266+
}
267+
return result;
268+
}
269+
251270
template <typename T>
252271
auto get_deprecated_message(T const& row)
253272
{
254273
auto attr = get_attribute(row, "Windows.Foundation.Metadata", "DeprecatedAttribute");
255-
return get_attribute_value<std::string_view>(attr, 0);
274+
return escape_cpp_string_literal(get_attribute_value<std::string_view>(attr, 0));
256275
}
257276

258277
template <typename T>

0 commit comments

Comments
 (0)