// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncheckedCallArgsChecker -std=c++20 -verify %s // expected-no-diagnostics // Previously [[clang::suppress]] failed for implicit template specializations when // namespace has multiple redeclarations and suppression is in a different // redeclaration than the lexical parent of the implicit specialization. // // The bug occurred when: // 1. A template is forward-declared in one namespace block // 2. A partial specialization with [[clang::suppress]] is in a different block // 3. An implicit instantiation's getLexicalDeclContext() points to the wrong block typedef __SIZE_TYPE__ size_t; namespace std { template struct remove_cvref { using type = T; }; template struct remove_cvref { using type = T; }; template using remove_cvref_t = typename remove_cvref::type; template struct tuple {}; template struct tuple_element; template struct tuple_element<0, tuple> { using type = T; }; template struct tuple_element> : tuple_element> {}; template using tuple_element_t = typename tuple_element::type; template struct optional { T v; T&& operator*() && { return static_cast(v); } operator bool() const { return true; } }; template optional make_optional(As...); } // namespace std namespace WTF { template T&& move(T&); } void WTFCrash(); template struct CanMakeCheckedPtrBase { void incrementCheckedPtrCount() const { ++m; } void decrementCheckedPtrCount() const { if (!m) WTFCrash(); --m; } mutable T m{}; }; struct Checked : CanMakeCheckedPtrBase {}; Checked* get(); // First namespace block - forward declaration # 1 "Header1.h" 1 namespace N { template struct C; template struct C { template static std::optional decode(D&) { return {get()}; } }; } // namespace N # 50 "test.cpp" 2 // Second namespace block - this becomes the lexical parent for implicit specializations # 1 "Header2.h" 1 namespace N { template struct C; struct Dec { template std::optional decode() { return {C>::decode(*this)}; } }; } // namespace N # 100 "test.cpp" 2 // Third namespace block - [[clang::suppress]] is here # 1 "Header3.h" 1 namespace N { template struct C> { template static std::optional> decode(D& d, std::optional&&... os) { if constexpr (sizeof...(Os) < sizeof...(Es)) { auto o = d.template decode>>(); if (!o) return {}; return decode(d, WTF::move(os)..., WTF::move(o)); } else { // This [[clang::suppress]] should suppress the warning. // Bug: Without the fix, it doesn't work because the implicit // specialization's lexical parent points to Header2.h's namespace block. [[clang::suppress]] return std::make_optional>(*WTF::move(os)...); } } }; } // namespace N # 150 "test.cpp" 2 void rdar_168941095() { N::Dec d; (void)d.decode>(); }