diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -113,6 +113,8 @@ This fixes Issue `Issue 54462 `_. - Statement expressions are now disabled in default arguments in general. This fixes Issue `Issue 53488 `_. +- Unknown attributes with [[]] spelling now will only be warned once. + This fixes Issue `Issue 54817 `_. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2633,8 +2633,12 @@ // Forbid C++11 and C2x attributes that appear on certain syntactic locations // which standard permits but we don't supported yet, for example, attributes // appertain to decl specifiers. + // For the most cases we don't want to warn on unknown attributes, but left + // them to later diagnoses. However, for a few cases like module declarations + // and module import declarations, we should do it. void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, - bool DiagnoseEmptyAttrs = false); + bool DiagnoseEmptyAttrs = false, + bool WarnOnUnknownAttrs = false); /// Skip C++11 and C2x attributes and return the end location of the /// last one. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1658,7 +1658,8 @@ } void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, - bool DiagnoseEmptyAttrs) { + bool DiagnoseEmptyAttrs, + bool WarnOnUnknownAttrs) { if (DiagnoseEmptyAttrs && Attrs.empty() && Attrs.Range.isValid()) { // An attribute list has been parsed, but it was empty. @@ -1685,10 +1686,11 @@ for (const ParsedAttr &AL : Attrs) { if (!AL.isCXX11Attribute() && !AL.isC2xAttribute()) continue; - if (AL.getKind() == ParsedAttr::UnknownAttribute) - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) - << AL << AL.getRange(); - else { + if (AL.getKind() == ParsedAttr::UnknownAttribute) { + if (WarnOnUnknownAttrs) + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL << AL.getRange(); + } else { Diag(AL.getLoc(), DiagID) << AL; AL.setInvalid(); } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2377,7 +2377,9 @@ // We don't support any module attributes yet; just parse them and diagnose. ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr); + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr, + /*DiagnoseEmptyAttrs=*/false, + /*WarnOnUnknownAttrs=*/true); ExpectAndConsumeSemi(diag::err_module_expected_semi); @@ -2444,7 +2446,9 @@ ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); // We don't support any module import attributes yet. - ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr); + ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr, + /*DiagnoseEmptyAttrs=*/false, + /*WarnOnUnknownAttrs=*/true); if (PP.hadModuleLoaderFatalFailure()) { // With a fatal failure in the module loader, we abort parsing. diff --git a/clang/test/SemaCXX/warn-once-on-unknown-attr.cpp b/clang/test/SemaCXX/warn-once-on-unknown-attr.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/warn-once-on-unknown-attr.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify -std=c2x -x c %s +void foo() { + int [[attr]] i; // expected-warning {{unknown attribute 'attr' ignored}} + (void)sizeof(int [[attr]]); // expected-warning {{unknown attribute 'attr' ignored}} +} + + +void bar() { + [[attr]]; // expected-warning {{unknown attribute 'attr' ignored}} + [[attr]] int i; // expected-warning {{unknown attribute 'attr' ignored}} +}