diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -767,9 +767,9 @@ // Deprecations warnings are always enabled, except when users explicitly opt-out // by defining _LIBCPP_DISABLE_DEPRECATION_WARNINGS. # if !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS) -# if __has_attribute(deprecated) -# define _LIBCPP_DEPRECATED __attribute__((deprecated)) -# define _LIBCPP_DEPRECATED_(m) __attribute__((deprecated(m))) +# if __has_attribute(__deprecated__) +# define _LIBCPP_DEPRECATED __attribute__((__deprecated__)) +# define _LIBCPP_DEPRECATED_(m) __attribute__((__deprecated__(m))) # elif _LIBCPP_STD_VER > 11 # define _LIBCPP_DEPRECATED [[deprecated]] # define _LIBCPP_DEPRECATED_(m) [[deprecated(m)]] diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -404,7 +404,7 @@ }; #if defined(_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI) -# define _LIBCPP_SHARED_PTR_TRIVIAL_ABI __attribute__((trivial_abi)) +# define _LIBCPP_SHARED_PTR_TRIVIAL_ABI __attribute__((__trivial_abi__)) #else # define _LIBCPP_SHARED_PTR_TRIVIAL_ABI #endif diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h --- a/libcxx/include/__memory/unique_ptr.h +++ b/libcxx/include/__memory/unique_ptr.h @@ -115,7 +115,7 @@ }; #if defined(_LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI) -# define _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI __attribute__((trivial_abi)) +# define _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI __attribute__((__trivial_abi__)) #else # define _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI #endif diff --git a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt --- a/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt +++ b/libcxx/test/tools/clang_tidy_checks/CMakeLists.txt @@ -8,8 +8,9 @@ set(SOURCES abi_tag_on_virtual.cpp hide_from_abi.cpp - robust_against_adl.cpp qualify_declval.cpp + robust_against_adl.cpp + uglify_attributes.cpp libcpp_module.cpp ) diff --git a/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp --- a/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp +++ b/libcxx/test/tools/clang_tidy_checks/libcpp_module.cpp @@ -13,6 +13,7 @@ #include "hide_from_abi.hpp" #include "robust_against_adl.hpp" #include "qualify_declval.hpp" +#include "uglify_attributes.hpp" namespace { class LibcxxTestModule : public clang::tidy::ClangTidyModule { @@ -21,6 +22,7 @@ check_factories.registerCheck("libcpp-avoid-abi-tag-on-virtual"); check_factories.registerCheck("libcpp-hide-from-abi"); check_factories.registerCheck("libcpp-robust-against-adl"); + check_factories.registerCheck("libcpp-uglify-attributes"); check_factories.registerCheck("libcpp-qualify-declval"); } }; diff --git a/libcxx/test/tools/clang_tidy_checks/uglify_attributes.hpp b/libcxx/test/tools/clang_tidy_checks/uglify_attributes.hpp new file mode 100644 --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/uglify_attributes.hpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang-tidy/ClangTidyCheck.h" + +namespace libcpp { +class uglify_attributes : public clang::tidy::ClangTidyCheck { +public: + uglify_attributes(llvm::StringRef, clang::tidy::ClangTidyContext*); + void registerMatchers(clang::ast_matchers::MatchFinder*) override; + void check(const clang::ast_matchers::MatchFinder::MatchResult&) override; +}; +} // namespace libcpp diff --git a/libcxx/test/tools/clang_tidy_checks/uglify_attributes.cpp b/libcxx/test/tools/clang_tidy_checks/uglify_attributes.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/tools/clang_tidy_checks/uglify_attributes.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang-tidy/ClangTidyCheck.h" +#include "clang-tidy/ClangTidyModuleRegistry.h" + +#include "uglify_attributes.hpp" + +#include +#include + +namespace { +bool isUgly(std::string_view str) { + if (str.size() < 2) + return false; + if (str[0] == '_' && str[1] >= 'A' && str[1] <= 'Z') + return true; + return str.find("__") != std::string_view::npos; +} + +AST_MATCHER(clang::Attr, isPretty) { + if (Node.isKeywordAttribute()) + return false; + if (Node.isCXX11Attribute() && !Node.hasScope()) // TODO: reject standard attributes that are version extensions + return false; + if (Node.hasScope()) + if (!isUgly(Node.getScopeName()->getName())) + return true; + + if (Node.getAttrName()) + return !isUgly(Node.getAttrName()->getName()); + + return false; +} + +std::optional getUglyfiedCXX11Attr(const clang::Attr& attr) { + // Don't try to fix attributes with `using` in them. + if (std::ranges::search(std::string_view(attr.getSpelling()), std::string_view("::")).empty()) + return std::nullopt; + + std::string attr_string; + if (attr.isClangScope()) + attr_string += "_Clang::"; + else if (attr.isGNUScope()) + attr_string += "__gnu__::"; + + if (!attr.getAttrName()->getName().starts_with("__")) { + attr_string += "__"; + attr_string += attr.getAttrName()->getName(); + attr_string += "__"; + } else { + attr_string += attr.getAttrName()->getName(); + } + return std::move(attr_string); +} + +std::optional getUglyfiedGNUAttr(const clang::Attr& attr) { + return "__" + attr.getAttrName()->getName().str() + "__"; +} + +std::optional getUglified(const clang::Attr& attr) { + if (attr.isCXX11Attribute()) { + return getUglyfiedCXX11Attr(attr); + } else if (attr.isGNUAttribute()) { + return getUglyfiedGNUAttr(attr); + } + + return std::nullopt; +} +} // namespace + +namespace libcpp { +uglify_attributes::uglify_attributes(llvm::StringRef name, clang::tidy::ClangTidyContext* context) + : clang::tidy::ClangTidyCheck(name, context) {} + +void uglify_attributes::registerMatchers(clang::ast_matchers::MatchFinder* finder) { + using namespace clang::ast_matchers; + finder->addMatcher(attr(isPretty()).bind("normal_attribute"), this); +} + +void uglify_attributes::check(const clang::ast_matchers::MatchFinder::MatchResult& result) { + if (const auto* call = result.Nodes.getNodeAs("normal_attribute"); call != nullptr) { + auto diagnostic = diag(call->getLoc(), "Non-standard attributes should use the _Ugly spelling"); + auto uglified = getUglified(*call); + if (uglified.has_value()) { + diagnostic << clang::FixItHint::CreateReplacement(call->getRange(), *uglified); + } + } +} +} // namespace libcpp