Skip to content

Commit a63fc0e

Browse files
wchilders-nvidiadaveedvdv-nvidia
authored andcommitted
Fix C++-generating back end issue with inaccessible or out-of-scope template arguments [GH #191]
1 parent 62a1c13 commit a63fc0e

6 files changed

Lines changed: 115 additions & 11 deletions

File tree

‎src/Changes‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
Version 7.1
22

3+
10/5/26 [GH #191]
4+
C++-generating back end: inaccessible or out-of-scope template arguments
5+
6+
In certain complex cases, the C++-generating back end could put out a
7+
template argument that uses an inaccessible or out-of-scope name, making
8+
the generated code uncompilable. This is now fixed.
9+
10+
311
10/5/26 [GH #213]
412
White space lost in the pragma text for a "#pragma clang" directive
513

‎src/cp_gen_be.c‎

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9911,6 +9911,29 @@ elaborated-type-specifier, even if it would be required in some contexts.
99119911
specified in the reference; a null template argument list
99129912
implies an empty list, "<>", not that it was omitted. */
99139913
arg_list = trp->variant.typeref.extra_info->template_arg_list;
9914+
if (arg_list != NULL) {
9915+
a_template_arg_ptr tap;
9916+
a_boolean for_all_scopes = TRUE;
9917+
begin_template_arg_list_traversal_simple(arg_list, &tap);
9918+
while (tap != NULL) {
9919+
if (!template_arg_is_accessible(
9920+
tap, /*ignore_context=*/FALSE,
9921+
/*check_related_types=*/FALSE,
9922+
&for_all_scopes, /*check_visibility=*/TRUE)) {
9923+
/* This template argument uses a name that is inaccessible or
9924+
out of scope, so the trk_template_arg_list cannot be used.
9925+
Recursively put out the underlying type (which might
9926+
include a trk_name_qualifier that should be preserved, so
9927+
we use the direct underlying type and not
9928+
skip_lexical_typerefs). */
9929+
gen_type_reference(trp->variant.typeref.type,
9930+
suppress_typename_kwd, is_declaration,
9931+
suppress_elab_type_spec);
9932+
goto done;
9933+
} /* if */
9934+
advance_to_next_template_arg_simple(&tap);
9935+
} /* while */
9936+
} /* if */
99149937
if (type_is(refp, tk_typeref) &&
99159938
is_typeref_kind(refp, trk_name_qualifier)) {
99169939
/* The target of the typeref specifies the qualifiers used in
@@ -10179,17 +10202,25 @@ elaborated-type-specifier, even if it would be required in some contexts.
1017910202
use_elab_type_spec = TRUE;
1018010203
} /* if */
1018110204
} else if (!suppress_elab_type_spec) {
10182-
/* See if the type is a member of a class or namespace. If so, we
10183-
need to push the hidden name information for that scope to see if
10184-
the elaborated type specifier is needed. */
10185-
a_scope_ptr scope = parent_scope_of(type);
10186-
if (scope != NULL) {
10187-
/* This type is a member of a class or namespace, so push the
10188-
hidden name information for that name context. */
10189-
push_name_context(scope);
10190-
} /* if */
10191-
use_elab_type_spec = type->elaborated_type_specifier_needed;
10192-
if (scope != NULL) pop_name_context();
10205+
if (is_tag_type(type) && is_declaration) {
10206+
/* The tag keyword is required in a declaration. Normally the recorded
10207+
form of the name reference puts out the tag keyword, but that path
10208+
may be bypassed when the recorded template argument list cannot be
10209+
used. */
10210+
use_elab_type_spec = TRUE;
10211+
} else {
10212+
/* See if the type is a member of a class or namespace. If so, we
10213+
need to push the hidden name information for that scope to see if
10214+
the elaborated type specifier is needed. */
10215+
a_scope_ptr scope = parent_scope_of(type);
10216+
if (scope != NULL) {
10217+
/* This type is a member of a class or namespace, so push the
10218+
hidden name information for that name context. */
10219+
push_name_context(scope);
10220+
} /* if */
10221+
use_elab_type_spec = type->elaborated_type_specifier_needed;
10222+
if (scope != NULL) pop_name_context();
10223+
} /* if */
1019310224
} /* if */
1019410225
if (!has_name_before_mangling(orig_type) &&
1019510226
synthesize_decltype_specifier(orig_type)) {
@@ -10218,6 +10249,9 @@ elaborated-type-specifier, even if it would be required in some contexts.
1021810249
/* A fundamental type. */
1021910250
form_type(type, &octl);
1022010251
} /* if */
10252+
#if DEFAULT_RECORD_FORM_OF_NAME_REFERENCE
10253+
done:;
10254+
#endif /* DEFAULT_RECORD_FORM_OF_NAME_REFERENCE */
1022110255
} /* gen_type_reference */
1022210256

1022310257

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpfe -DTEST_NUMBER=1 --c++17 --gnu_version=150200 Test_name.c
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=1 --c++20 Test_name.c
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//options_all:--c++17 --gnu_version=150200
2+
//type:cp
3+
template <bool, typename, typename> using a = int;
4+
template <bool, typename, typename> using b = int;
5+
template <typename...> using i = unsigned long;
6+
template <typename> constexpr bool d = false;
7+
template <typename e, typename f> constexpr bool j = __is_same(e, f);
8+
template <typename e, e...> struct h {};
9+
template <typename e, e ad> using ae = h<e, __integer_pack(ad)...>;
10+
template <long... af> using ag = h<unsigned long, af...>;
11+
template <long ad> using ah = ae<unsigned long, ad>;
12+
template <int ai, typename... aj> struct k {
13+
using g = __type_pack_element<ai, aj...>;
14+
};
15+
typedef unsigned long al;
16+
template <typename...> class l;
17+
template <typename> long ao;
18+
template <typename... aj> constexpr long ao<l<aj...>> = sizeof...(aj);
19+
template <unsigned long, typename> struct m;
20+
template <unsigned long ai, typename... aj> struct m<ai, l<aj...>> {
21+
using g = typename k<ai, aj...>::g;
22+
};
23+
template <long ai, typename aq> using ar = typename m<ai, aq>::g;
24+
template <typename... aj> l<aj...> as(l<aj...>);
25+
template <long ai, typename aq, typename at = decltype(aq()),
26+
typename e = ar<ai, at>>
27+
using au = a<d<aq>, e, e>;
28+
template <typename e, typename... aj> bool ay = (j<e, aj> && ...);
29+
template <typename av, typename aq, unsigned long... az>
30+
constexpr bool ba(ag<az...>) {
31+
(void)ay<i<av, au<az, aq>>...>;
32+
return false;
33+
}
34+
template <typename...> class l {};
35+
template <typename av, typename... aw> constexpr av bb(av x, aw...) {
36+
using bc = decltype(as(aw()...));
37+
ba<av, bc>(ah<ao<bc>>());
38+
return x;
39+
}
40+
struct {
41+
using bd = l<al, long>;
42+
bd c;
43+
} be;
44+
void e() {
45+
struct n {};
46+
bb(n{}, be.c);
47+
}
48+
using bh = b<j<unsigned long, al>, int, long>;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//type:fp
2+
//options:--c++20
3+
template<typename T> class S
4+
{ };
5+
6+
class C {
7+
private:
8+
struct N;
9+
S<N> f();
10+
};
11+
12+
extern template class S<C::N>;

0 commit comments

Comments
 (0)