// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s void clang_analyzer_warnIfReached(); // ============================================================================ // Group A: Basic class template — attribute on primary // ============================================================================ // Placeholder types for triggering instantiations. // - Type{A,B} should match an unconstrained template type parameter. // - Specialized{A,B} should match some specialization pattern. struct TypeA{}; struct TypeB{}; struct SpecializedA{}; struct SpecializedB{}; template class [[clang::suppress]] A_Primary { public: void inline_method() { clang_analyzer_warnIfReached(); // no-warning } void outline_method(); static void static_inline() { clang_analyzer_warnIfReached(); // no-warning } static void static_outline(); }; template void A_Primary::outline_method() { // Out-of-line: lexical context is the translation unit. clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } template void A_Primary::static_outline() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } void test_A() { A_Primary().inline_method(); A_Primary().outline_method(); A_Primary::static_inline(); A_Primary::static_outline(); // Different instantiation. A_Primary().inline_method(); } // ============================================================================ // Group B: Explicit full specialization — attribute isolation // ============================================================================ // --- B1: attribute on primary only --- template class [[clang::suppress]] B1_AttrOnPrimary { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; // Explicit specialization is independent — NOT suppressed. template <> struct B1_AttrOnPrimary { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_B1() { B1_AttrOnPrimary().method(); // suppressed (primary) B1_AttrOnPrimary().method(); // warns (spec, no attr) } // --- B2: attribute on specialization only --- template struct B2_AttrOnSpec { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; template <> class [[clang::suppress]] B2_AttrOnSpec { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; void test_B2() { B2_AttrOnSpec().method(); // warns (primary, no attr) B2_AttrOnSpec().method(); // suppressed (spec has attr) } // --- B3: attribute on both primary and specialization --- template class [[clang::suppress]] B3_AttrOnBoth { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; template <> class [[clang::suppress]] B3_AttrOnBoth { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; void test_B3() { B3_AttrOnBoth().method(); // suppressed B3_AttrOnBoth().method(); // suppressed } // ============================================================================ // Group C: Partial specializations // ============================================================================ // --- C1: attribute on partial specialization only --- template struct C1_AttrOnPartial { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; template class [[clang::suppress]] C1_AttrOnPartial { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; void test_C1() { C1_AttrOnPartial().method(); // warns (primary, no attr) C1_AttrOnPartial().method(); // suppressed (partial spec) } // --- C2: attribute on primary, partial spec has none --- template class [[clang::suppress]] C2_AttrOnPrimary { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; template struct C2_AttrOnPrimary { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_C2() { C2_AttrOnPrimary().method(); // suppressed (primary) C2_AttrOnPrimary().method(); // warns (partial spec, no attr) } // --- C3: two partial specializations, only one suppressed --- template struct C3_TwoPartials { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; template class [[clang::suppress]] C3_TwoPartials { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; template struct C3_TwoPartials { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_C3() { C3_TwoPartials().method(); // warns (primary) C3_TwoPartials().method(); // suppressed (first partial) C3_TwoPartials().method(); // warns (second partial, no attr) } // ============================================================================ // Group D: Forward-declared class template (chooseDefinitionRedecl path) // ============================================================================ // The template is forward-declared, then defined. chooseDefinitionRedecl() // must find the definition among the redeclarations. // --- D1: Forward-declared without attribute, defined with attribute --- template class D1_ForwardDeclared; template class [[clang::suppress]] D1_ForwardDeclared { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; void test_D1() { D1_ForwardDeclared().method(); } // --- D2: Forward-declared without attribute, defined without attribute --- template struct D2_ForwardDeclared_NoAttr; template struct D2_ForwardDeclared_NoAttr { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_D2() { D2_ForwardDeclared_NoAttr().method(); } // ============================================================================ // Group E: Specialization with out-of-line (OOL) methods // ============================================================================ template class [[clang::suppress]] E_SpecWithOOL { public: void inline_method() { clang_analyzer_warnIfReached(); // no-warning } void outline_method(); }; template void E_SpecWithOOL::outline_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } // Explicit specialization with attribute and out-of-line method. template <> class [[clang::suppress]] E_SpecWithOOL { public: void inline_method() { clang_analyzer_warnIfReached(); // no-warning } void outline_method(); }; // Out-of-line for the specialization — not suppressed. void E_SpecWithOOL::outline_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } void test_E() { E_SpecWithOOL().inline_method(); E_SpecWithOOL().outline_method(); E_SpecWithOOL().inline_method(); E_SpecWithOOL().outline_method(); } // ============================================================================ // Group F: Nested class inside class template specialization // ============================================================================ template class [[clang::suppress]] F_Outer { public: struct Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; }; template struct F_Outer_NoAttr { struct Inner { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; }; void test_F() { F_Outer::Inner().method(); F_Outer_NoAttr::Inner().method(); } // ============================================================================ // Group G: Class template with default template arguments // ============================================================================ template class [[clang::suppress]] G_WithDefault { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; template struct G_WithDefault_NoAttr { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_G() { G_WithDefault().method(); // uses default U=TypeA G_WithDefault().method(); // explicit U=TypeB G_WithDefault_NoAttr().method(); // uses default U=TypeA } // ============================================================================ // Group H: Explicit instantiation directive // ============================================================================ template class [[clang::suppress]] H_ExplicitInst { public: void method() { clang_analyzer_warnIfReached(); // no-warning } }; // Explicit instantiation. template class H_ExplicitInst; void test_H() { H_ExplicitInst().method(); }