// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s void clang_analyzer_warnIfReached(); // Placeholder types for triggering instantiations. // - Type{A,B,C,D} should match an unconstrained template type parameter. struct TypeA{}; struct TypeB{}; struct TypeC{}; struct TypeD{}; // ============================================================================ // Group A: 2-level nesting — attribute on outer // ============================================================================ template struct [[clang::suppress]] TwoLevel_AttrOuter { template struct Inner { void inline_method() { clang_analyzer_warnIfReached(); // no-warning } void outline_method(); }; void outer_inline() { clang_analyzer_warnIfReached(); // no-warning } void outer_outline(); }; template template void TwoLevel_AttrOuter::Inner::outline_method() { // Out-of-line: lexical context is namespace, not the class. clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } template void TwoLevel_AttrOuter::outer_outline() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } void test_two_level_outer() { TwoLevel_AttrOuter::Inner().inline_method(); TwoLevel_AttrOuter::Inner().outline_method(); TwoLevel_AttrOuter().outer_inline(); TwoLevel_AttrOuter().outer_outline(); } // ============================================================================ // Group B: 2-level nesting — attribute on inner // ============================================================================ template struct TwoLevel_AttrInner { template struct [[clang::suppress]] Inner { void inline_method() { clang_analyzer_warnIfReached(); // no-warning } void outline_method(); }; void outer_inline() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; template template void TwoLevel_AttrInner::Inner::outline_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } void test_two_level_inner() { TwoLevel_AttrInner::Inner().inline_method(); TwoLevel_AttrInner::Inner().outline_method(); TwoLevel_AttrInner().outer_inline(); } // ============================================================================ // Group C: 3-level nesting — attribute at each level // ============================================================================ // --- C1: attribute on outermost --- template struct [[clang::suppress]] ThreeLevel_AttrOuter { template struct Mid { template struct Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; void mid_method() { clang_analyzer_warnIfReached(); // no-warning } }; }; void test_three_level_outer() { ThreeLevel_AttrOuter::Mid::Inner().method(); ThreeLevel_AttrOuter::Mid().mid_method(); } // --- C2: attribute on middle --- template struct ThreeLevel_AttrMid { template struct [[clang::suppress]] Mid { template struct Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; void mid_method() { clang_analyzer_warnIfReached(); // no-warning } }; void outer_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_three_level_mid() { ThreeLevel_AttrMid::Mid::Inner().method(); ThreeLevel_AttrMid::Mid().mid_method(); ThreeLevel_AttrMid().outer_method(); } // --- C3: attribute on innermost --- template struct ThreeLevel_AttrInner { template struct Mid { template struct [[clang::suppress]] Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; void mid_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void outer_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_three_level_inner() { ThreeLevel_AttrInner::Mid::Inner().method(); ThreeLevel_AttrInner::Mid().mid_method(); ThreeLevel_AttrInner().outer_method(); } // --- C4: no attribute at any level (negative test) --- template struct ThreeLevel_NoAttr { template struct Mid { template struct Inner { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void mid_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void outer_method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; void test_three_level_none() { ThreeLevel_NoAttr::Mid::Inner().method(); ThreeLevel_NoAttr::Mid().mid_method(); ThreeLevel_NoAttr().outer_method(); } // ============================================================================ // Group D: Mixed template / non-template nesting // ============================================================================ // --- D1: non-template outer, template inner --- struct [[clang::suppress]] NonTmplOuter_TmplInner { template struct Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; }; struct NonTmplOuter_TmplInner_NoAttr { template struct Inner { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; }; void test_mixed_nontmpl_outer() { NonTmplOuter_TmplInner::Inner().method(); NonTmplOuter_TmplInner_NoAttr::Inner().method(); } // --- D2: template outer, non-template inner --- template struct [[clang::suppress]] TmplOuter_NonTmplInner { struct Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; }; template struct TmplOuter_NonTmplInner_NoAttr { struct Inner { void method() { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; }; void test_mixed_tmpl_outer() { TmplOuter_NonTmplInner::Inner().method(); TmplOuter_NonTmplInner_NoAttr::Inner().method(); } // ============================================================================ // Group E: Multiple instantiations of the same nested template // ============================================================================ // Ensure suppression applies across different instantiation parameters. template struct [[clang::suppress]] MultiInst { template struct Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; }; void test_multi_inst() { MultiInst::Inner().method(); MultiInst::Inner().method(); MultiInst::Inner().method(); MultiInst::Inner().method(); } // ============================================================================ // Group F: Nested template with methods that have their own template params // ============================================================================ template struct [[clang::suppress]] NestedWithTemplateMethods { template struct Inner { template void tmpl_method(C) { clang_analyzer_warnIfReached(); // no-warning } }; }; template struct NestedWithTemplateMethods_NoAttr { template struct Inner { template void tmpl_method(C) { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } }; }; void test_nested_tmpl_methods() { NestedWithTemplateMethods::Inner().tmpl_method(TypeC{}); NestedWithTemplateMethods::Inner().tmpl_method(TypeD{}); NestedWithTemplateMethods_NoAttr::Inner().tmpl_method(TypeC{}); } // ============================================================================ // Group G: Attribute on both outer and inner (redundant but should work) // ============================================================================ template struct [[clang::suppress]] BothSuppressed { template struct [[clang::suppress]] Inner { void method() { clang_analyzer_warnIfReached(); // no-warning } }; void outer_method() { clang_analyzer_warnIfReached(); // no-warning } }; void test_both_suppressed() { BothSuppressed::Inner().method(); BothSuppressed().outer_method(); } // ============================================================================ // Regression test for gh#182659 // ============================================================================ // Nested template structs where the inner method accesses a member of a // different specialization — verifies that the suppression mechanism does not // accidentally suppress legitimate warnings when walking instantiation chains. template struct gh_182659_s1 { template struct gh_182659_s2 { int i; template int m(const gh_182659_s2& s2) { return s2.i; // expected-warning{{Undefined or garbage value returned to caller}} } }; }; void gh_182659() { gh_182659_s1::gh_182659_s2 s1; gh_182659_s1::gh_182659_s2 s2; s1.m(s2); }