Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Confused about ill-formed templates

7 views
Skip to first unread message

Johannes Schaub (litb)

unread,
Mar 27, 2010, 2:43:54 PM3/27/10
to
I'm confused about this statement of the Standard in 14.6/7:

"No diagnostic shall be issued for a template definition for which a valid
specialization can be generated. If no valid specialization can be generated
for a template definition, and that template is not instantiated, the
template definition is ill-formed, no diagnostic required. [...] [Note: if
a template is instantiated, errors will be diagnosed according to the other
rules in this Standard. Exactly when these errors are diagnosed is a quality
of implementation issue. ]"

And then it shows an example along this line:

template<typename T>
void f(T t) { +; }

It says about that

"may be diagnosed even if f is not instantiated".


Why does it say "may"? I thought this was a syntax error and it has to be
diagnosed disregarding of any instantiation. In the paragraph it says "If no
valid specialization can be generated for a template definition" however the
above is not a template definition because it doesn't parse! It's a syntax
error.

It also says in the note "If the template is instantiated, errors will be
diagnosed according to the other rules in this Standard", but to my
knowledge, if one violates a rule for which no diagnostic is required, the
Standard places no requirements on an implementation according to 1.4/2. So
why does it say that errors will be diagnosed?

I'm confused. Can anyone help me please?

--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Steve Clamage

unread,
Mar 29, 2010, 3:01:39 PM3/29/10
to
On Sat, 27 Mar 2010 12:43:54 CST, "Johannes Schaub (litb)"
<schaub-...@web.de> wrote:

>I'm confused about this statement of the Standard in 14.6/7:
>
>"No diagnostic shall be issued for a template definition for which a valid
>specialization can be generated. If no valid specialization can be generated
>for a template definition, and that template is not instantiated, the
>template definition is ill-formed, no diagnostic required. [...] [Note: if
>a template is instantiated, errors will be diagnosed according to the other
>rules in this Standard. Exactly when these errors are diagnosed is a quality
>of implementation issue. ]"

The intent of the seemingly odd wording here is to allow lazy template
processing. Consider the number of template definitions involved when
you include a standard header. Most of them will not be instantiated.
Translation can be more efficient if processing can be delayed until a
template is instantiated. A compiler is allowed -- but not required --
to diagnose a construct that could never be correct, if the template
is not instantiated.

In addition, grey areas probably exist, where a compler would have to
do substantial analysis to determine whether some valid instantiation
was possible (to avoid false positives). With the provision referenced
here, the compiler can wait until instantiation time.

>
>And then it shows an example along this line:
>
>template<typename T>
>void f(T t) { +; }
>
>It says about that
>
>"may be diagnosed even if f is not instantiated".
>
>
>Why does it say "may"? I thought this was a syntax error and it has to be
>diagnosed disregarding of any instantiation. In the paragraph it says "If no
>valid specialization can be generated for a template definition" however the
>above is not a template definition because it doesn't parse! It's a syntax
>error.

That's a quibble.

>
>It also says in the note "If the template is instantiated, errors will be
>diagnosed according to the other rules in this Standard", but to my
>knowledge, if one violates a rule for which no diagnostic is required, the
>Standard places no requirements on an implementation according to 1.4/2. So
>why does it say that errors will be diagnosed?
>
>I'm confused. Can anyone help me please?

This part of the standard makes a special case, intermediate between
non-template functions and instantiated templates. In those cases,
errors require a diagnostic unless otherwise specified. The
intermediate case is a template definition that is not instantiated.
Error reporting becomes optional in that special case.

Daniel Krügler

unread,
Mar 29, 2010, 3:12:03 PM3/29/10
to
On 27 Mrz., 20:43, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:

> I'm confused about this statement of the Standard in 14.6/7:
>
> "No diagnostic shall be issued for a template definition for which a valid
> specialization can be generated. If no valid specialization can be generated
> for a template definition, and that template is not instantiated, the
> template definition is ill-formed, no diagnostic required. [...] [Note: if
> a template is instantiated, errors will be diagnosed according to the other
> rules in this Standard. Exactly when these errors are diagnosed is a quality
> of implementation issue. ]"
>
> And then it shows an example along this line:
>
> template<typename T>
> void f(T t) { +; }
>
> It says about that
>
> "may be diagnosed even if f is not instantiated".
>
> Why does it say "may"? I thought this was a syntax error and it has to be
> diagnosed disregarding of any instantiation. In the paragraph it says "If no
> valid specialization can be generated for a template definition" however the
> above is not a template definition because it doesn't parse! It's a syntax
> error.
>
> It also says in the note "If the template is instantiated, errors will be
> diagnosed according to the other rules in this Standard", but to my
> knowledge, if one violates a rule for which no diagnostic is required, the
> Standard places no requirements on an implementation according to 1.4/2. So
> why does it say that errors will be diagnosed?
>
> I'm confused. Can anyone help me please?

I'm not an expert in C++ parsing, so I asked one:

The answer is that it is indeed a possible technique
to cache all tokens of the function body of a function
template until the matching closing brace has been
found. This supports parsers that don't validate the
function template body until implementation
instantiation is required. So the rule for not requiring
a diagnostic here exists to allow this kind of
implementation. Most recent compilers don't take
advantage of this freedom nowadays and will
produce a diagnostic, even though the template
has not been instantiated. The example exists to
allow for exactly this strategy as well.

HTH & Greetings from Bremen,

Daniel Krügler

Johannes Schaub (litb)

unread,
Mar 30, 2010, 12:49:31 PM3/30/10
to
Steve Clamage wrote:

> On Sat, 27 Mar 2010 12:43:54 CST, "Johannes Schaub (litb)"
> <schaub-...@web.de> wrote:
>
>>I'm confused about this statement of the Standard in 14.6/7:
>>
>>"No diagnostic shall be issued for a template definition for which a valid
>>specialization can be generated. If no valid specialization can be
>>generated for a template definition, and that template is not
>>instantiated, the
>>template definition is ill-formed, no diagnostic required. [...] [Note:
>>if a template is instantiated, errors will be diagnosed according to the
>>other rules in this Standard. Exactly when these errors are diagnosed is a
>>quality of implementation issue. ]"
>
> The intent of the seemingly odd wording here is to allow lazy template
> processing. Consider the number of template definitions involved when
> you include a standard header. Most of them will not be instantiated.
> Translation can be more efficient if processing can be delayed until a
> template is instantiated. A compiler is allowed -- but not required --
> to diagnose a construct that could never be correct, if the template
> is not instantiated.
>
> In addition, grey areas probably exist, where a compler would have to
> do substantial analysis to determine whether some valid instantiation
> was possible (to avoid false positives). With the provision referenced
> here, the compiler can wait until instantiation time.
>

Ah, thanks. This makes sense. I haven't thought about the speed thingies in
particular.


>>
>>And then it shows an example along this line:
>>
>>template<typename T>
>>void f(T t) { +; }
>>
>>It says about that
>>
>>"may be diagnosed even if f is not instantiated".
>>
>>
>>Why does it say "may"? I thought this was a syntax error and it has to be
>>diagnosed disregarding of any instantiation. In the paragraph it says "If
>>no valid specialization can be generated for a template definition"
>>however the above is not a template definition because it doesn't parse!
>>It's a syntax error.
>
> That's a quibble.
>

Hmm, i think i agree now that i read it again :)

>>
>>It also says in the note "If the template is instantiated, errors will be
>>diagnosed according to the other rules in this Standard", but to my
>>knowledge, if one violates a rule for which no diagnostic is required, the
>>Standard places no requirements on an implementation according to 1.4/2.
>>So why does it say that errors will be diagnosed?
>>
>>I'm confused. Can anyone help me please?
>
> This part of the standard makes a special case, intermediate between
> non-template functions and instantiated templates. In those cases,
> errors require a diagnostic unless otherwise specified. The
> intermediate case is a template definition that is not instantiated.
> Error reporting becomes optional in that special case.
>

Oh thanks for clarifying that. I would propose to make that note normative
though. It seems to me that the note "exactly when these errors are
diagnosed is a quality of implementation issue" can be read as "exactly
*whether* these errors..." by a don't-parse-definitions implementation since
there doesn't seem to be normative wording backing this up at all.

Nikolay Ivchenkov

unread,
Mar 30, 2010, 12:48:10 PM3/30/10
to
On 29 Mar, 23:01, Steve Clamage <stephen.clam...@sun.com> wrote:
> On Sat, 27 Mar 2010 12:43:54 CST, "Johannes Schaub (litb)"
> >And then it shows an example along this line:
>
> >template<typename T>
> >void f(T t) { +; }
>
> >It says about that
>
> >"may be diagnosed even if f is not instantiated".
>
> >Why does it say "may"? I thought this was a syntax error and it has to be
> >diagnosed disregarding of any instantiation. In the paragraph it says "If no
> >valid specialization can be generated for a template definition" however the
> >above is not a template definition because it doesn't parse! It's a syntax
> >error.
>
> That's a quibble.

Why? I think, the question of Johannes Schaub is completely
reasonable. What can you tell us about the following example?

template <class T> +;

Is it template-declaration? Shall this ill-formed construct be
diagnosed? How to determine whether some construct is template
definition? How to determine bounds of a template definition?

template <class T>
struct X
{
} // is end?
{
{
}; // is end?
}; // is end?

I don't see any reasons to think that

template<typename T>
void f(T t) { +; }

is template-declaration. Any template-declaration shall have the form

template-declaration:
export opt template < template-parameter-list > declaration

Otherwise the construct is not a template-declaration. Any declaration
shall have one of the form as described in Clause 7. Otherwise the
construct is not a declaration. Continuing similarly, I can conclude:

void f(T t) { +; }

is not a declaration and

template<typename T>
void f(T t) { +; }

is not a template-declaration. If I wrong, can you show exact set of
the rules that clearly requires to consider this construct as template
definition (or potential template definition)?

On 29 Mar, 23:12, Daniel Kr�gler <daniel.krueg...@googlemail.com>
wrote:


>
> The answer is that it is indeed a possible technique
> to cache all tokens of the function body of a function
> template until the matching closing brace has been
> found.

Is it just informal idea or there are strict formal criteria in the
standard or in the working draft?

Johannes Schaub (litb)

unread,
Mar 30, 2010, 12:48:54 PM3/30/10
to
Daniel Kr�gler wrote:

Ah, i see now, thanks for getting the well founded reason!

So i take this that a compiler is allowed to compile and not diagnose this

// this can never yield a valid specialization.
// It's ill-formed, no diagnostic required.
template<typename T>
int f() {
a++;
return 1;
}

int a;

int main() { int c[f<int>()];}

The part that says this is diagnosed "according to the other rules" when
instantiating is in a nonnormative note, so it doesn't count. Because no
diagnostic is required for the ill-formed template, the standard has no
requirements on the implementation processing the entire program anymore,
and an implementation is fine to accept this (including the ill-formed array
declarator).

Or is the wording about "no diagnostic required" not actually aimed to allow
to effectively yield undefined behavior? That's the major part that causes
confusion to me. Because as far as i know, the microsoft compiler does this
"skip from { to }" thingy, and i heard that that is non-conformant. But if
the standard grants them to accept the above code when read narrowly,
shouldn't MSVC be all-right doing that?

I mean, i see that the intention of the spec is to just let them go with the
ill-formed template, but require a diagnostic at instantiation. But to the
letter of the Standard, i see it allowing to go without any diagnostic at
all. I think the note should be normative. Or am i just missing something
really hard?

=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D

unread,
Mar 31, 2010, 8:01:22 PM3/31/10
to
On 30 Mrz., 18:48, Nikolay Ivchenkov <ts...@mail.ru> wrote:
> On 29 Mar, 23:01, Steve Clamage <stephen.clam...@sun.com> wrote:
>
> > On Sat, 27 Mar 2010 12:43:54 CST, "Johannes Schaub (litb)"
> > >And then it shows an example along this line:
>
> > >template<typename T>
> > >void f(T t) { +; }
>
> > >It says about that
>
> > >"may be diagnosed even if f is not instantiated".
>
> > >Why does it say "may"? I thought this was a syntax error and it has to
be
> > >diagnosed disregarding of any instantiation. In the paragraph it says
"If no
> > >valid specialization can be generated for a template definition"
however the
> > >above is not a template definition because it doesn't parse! It's a
syntax
> > >error.
>
> > That's a quibble.
>
> Why? I think, the question of Johannes Schaub is completely
> reasonable. What can you tell us about the following example?
>
> template <class T> +;
>
> Is it template-declaration? Shall this ill-formed construct be
> diagnosed? How to determine whether some construct is template
> definition? How to determine bounds of a template definition?

The standard does not give allowance for this to be undiagnosed.
The wording is ([temp.res]/8 in N3092):

"If no valid specialization can be generated for a template

definition,
and that template is not instantiated, the template definition is
ill-formed, no diagnostic required."

If the parser sees

template <class T> +;

it cannot decide whether this is a declaration or a definition,
but the above rule gives no allowance for undiagnosed
non-defining declarations, so this must be diagnosed.

> template <class T>
> struct X
> {
> } // is end?
> {
> {
> }; // is end?
> }; // is end?

This is currently QoI and it may lead to compiler
errors that point somewhere else, as you expected.

Assuming your comments where positions
where the compiler would decide for a ending
definition, the remaining tokens would again
produce something ill-formed and so a diagnostic
will occur. The standard says that such a
diagnostic is allowed. It is true, that the standard
does not give /precise/ descriptions how to
do that, but the only thing that might happen,
is that some not-instantiated but ill-formed code
/could/ remain undiagnosed, but no guarantee
for this is given.

> I don't see any reasons to think that
>
> template<typename T>
> void f(T t) { +; }
>
> is template-declaration. Any template-declaration shall have the form
>
> template-declaration:
> export opt template < template-parameter-list > declaration
>
> Otherwise the construct is not a template-declaration. Any declaration
> shall have one of the form as described in Clause 7. Otherwise the
> construct is not a declaration. Continuing similarly, I can conclude:

This is a definition of a valid template grammar, but that doesn't
proof that a compiler cannot allow for some relaxed parsing in
some parts of the code. If the code is ill-formed, it's ill-formed.
The compiler has a bug, if it does not diagnose violations of
diagnostic-required ill-formed code outside the scope of above
special rule. The rule does not give freedom to interpret the
code at will. So a compiler will only take advantage of this
rule, if it can proof (not necessarily in a mathematical sense),
that it can pack a token-soup in a bag for further inspection
if instantiated. If you can proof that the compiler does not
follow this, you have found a bug in the compiler (You may
also have found a bug in the standard, but AFAIK such a bug
is not yet documented related to this domain. I believe that
it is particular hard to proof a defect in the standard for this,
because the wording is both a allowance *and* a duty for
the compiler).

[Speaking of toke-soup is a good example: Usual html-readers
can handle token-soups to some extend but that does not make
the html code itself conforming.]

> void f(T t) { +; }

But this is not a template, so it's excluded from that rule.

> is not a declaration and
>
> template<typename T>
> void f(T t) { +; }
>
> is not a template-declaration. If I wrong, can you show exact set of
> the rules that clearly requires to consider this construct as template
> definition (or potential template definition)?

[..]

> > The answer is that it is indeed a possible technique
> > to cache all tokens of the function body of a function
> > template until the matching closing brace has been
> > found.
>
> Is it just informal idea or there are strict formal criteria in the
> standard or in the working draft?

I quoted above central and normative wording. I think the
standard is intentionally diffuse here to allow for different
implementation strategies. There is no rule that allows
for undiagnosed ill-formed code that would otherwise
be a require a diagnostic for instantiated code. If we
sometimes meet a compiler, where the seemingly
position of some ill-formed code is quite a distance
away from the actual defect, this can be the reason.

I have been told that newer compiler (generations)
tend to go away from taking advantage of this
explicit allowance rule to improve diagnostic
quality, but this isn't part of the spec.

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use

mailto:std...@netlab.cs.rpi.edu<std-c%2B%2...@netlab.cs.rpi.edu>

=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D

unread,
Mar 31, 2010, 8:11:25 PM3/31/10
to
On 30 Mrz., 18:48, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
> So i take this that a compiler is allowed to compile and not diagnose thi=

s
>
> // this can never yield a valid specialization.
> // It's ill-formed, no diagnostic required.
> template<typename T>
> int f() {
> a++;
> return 1;
> }
>
> int a;
>
> int main() { int c[f<int>()];}
>
> The part that says this is diagnosed "according to the other rules" when
> instantiating is in a nonnormative note, so it doesn't count.

"Doesn't count" is not what the standard says to notes. The note
does not say something new here, so it's just an informational
content that remembers us that *of-course* the rest of the
standard requirements apply. You could remove it without
changing the normative standard wording.

> Because no
> diagnostic is required for the ill-formed template, the standard has no
> requirements on the implementation processing the entire program anymore,
> and an implementation is fine to accept this (including the ill-formed
array
> declarator).

I don't see where you can conclude this from. [temp.res]/8 says
nothing like this:

"If no valid specialization can be generated for a template
definition,
and that template is not instantiated, the template definition is
ill-formed, no diagnostic required."

This rule applies if f would not be instantiated, but in your example
it is instantiated. So where is the wording that allows a compiler
to not diagnose otherwise ill-formed code requiring a diagnostic?

If the compiler instantiates f it is required to check all such
violations. You are right that without any instantiation of f
this diagnostic is *not* required.

> Or is the wording about "no diagnostic required" not actually aimed to
allow

> to effectively yield undefined behavior? That's the major part that cause=


s
> confusion to me. Because as far as i know, the microsoft compiler does
this

> "skip from { to }" thingy, and i heard that that is non-conformant. But i=


f
> the standard grants them to accept the above code when read narrowly,
> shouldn't MSVC be all-right doing that?

But the standard gives no freedom to let above violation of the rules
undiagnosed, so this is mood and it doesn't prevent the compiler XYZ
from being buggy/non-conforming.

> I mean, i see that the intention of the spec is to just let them go with
the

> ill-formed template, but require a diagnostic at instantiation. But to th=


e
> letter of the Standard, i see it allowing to go without any diagnostic at
> all. I think the note should be normative. Or am i just missing something
> really hard?

Let me say it differently: I cannot read your interpretation in the
standard wording. The above quoted sentence is a normative
sentence and is restricted to (a) template definitions, which are
(b) not yet instantiated. For the combinations of (a) and (b)
the wording allows for an undiagnosed ill-formed definition of
this template. I believe you might look from the wrong angle:
It's not the user who has to beg for a compiler that may consider
code ill-formed according to todays moon phase or other
criteria, it's vice versa: A compiler can only apply the rule,
if it can be sure that is within the allowed domain. That doesn't
mean that it can interpret the domain in a wishywash manner.
The C++ standard does not require that a compiler has to
use a mathematical proof that valid code is valid and invalid
code is invalid. It can use heuristics to it's wishes. Of-course
sometimes such a heuristic can be wrong, but then you
have found a bug in the compiler and that is something we
hit upon from day to day, right?

[And I guess that the current tendency of compilers to stay
more and more away from above latitude is related to the fact
that it tends to produce compiler bugs or bad diagnostic quality.
This follows naturally from the fact that the compiler has to
*guess* here.]

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use

mailto:std...@netlab.cs.rpi.edu<std-c%2B%2...@netlab.cs.rpi.edu>

Nikolay Ivchenkov

unread,
Apr 1, 2010, 12:49:33 AM4/1/10
to
On 1 Apr, 04:01, Daniel_Krugler <daniel.krueg...@googlemail.c=.om>
wrote:

> On 30 Mrz., 18:48, Nikolay Ivchenkov <ts...@mail.ru> wrote:
> > template <class T> +;
>
> > Is it template-declaration? Shall this ill-formed construct be
> > diagnosed? How to determine whether some construct is template
> > definition? How to determine bounds of a template definition?
>
> The standard does not give allowance for this to be undiagnosed.
> The wording is ([temp.res]/8 in N3092):
>
> "If no valid specialization can be generated for a template
> definition,
> and that template is not instantiated, the template definition is
> ill-formed, no diagnostic required."
>
> If the parser sees
>
> template <class T> +;
>
> it cannot decide whether this is a declaration or a definition,
> but the above rule gives no allowance for undiagnosed
> non-defining declarations, so this must be diagnosed.

According to your reasoning, when the compiler does not diagnose the
following

template<typename T>
void f(T t) { +; }

it must know that this construct is a declaration. So, is it a
declaration, and why exactly?

For each given program there are 3 mutually exclusive options:
1) the standard requires the ill-formed program to be diagnosed;
2) the standard does not require the ill-formed to be diagnosed (in
this case the behavior is undefined);
3) the standard has no strict answer about whether it requires ill-
formed program to be diagnosed (in this case the standard has a
defect).

Given the following program

template <class T>
struct X
{
{
} // is end?
{
{
}; // is end?
}; // is end?

int main()
{
}

what the standard/draft says about whether the diagnostic is required?


--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]

Johannes Schaub (litb)

unread,
Apr 1, 2010, 1:51:48 PM4/1/10
to
=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D wrote:

> On 30 Mrz., 18:48, "Johannes Schaub (litb)" <schaub-johan...@web.de>
> wrote:
>> Because no
>> diagnostic is required for the ill-formed template, the standard has no

>> requirements on the implementation processing the entire program anymore=


,
>> and an implementation is fine to accept this (including the ill-formed
> array
>> declarator).
>
> I don't see where you can conclude this from. [temp.res]/8 says
> nothing like this:
>
> "If no valid specialization can be generated for a template
> definition,
> and that template is not instantiated, the template definition is
> ill-formed, no diagnostic required."
>
> This rule applies if f would not be instantiated, but in your example
> it is instantiated. So where is the wording that allows a compiler
> to not diagnose otherwise ill-formed code requiring a diagnostic?
>
> If the compiler instantiates f it is required to check all such
> violations. You are right that without any instantiation of f
> this diagnostic is *not* required.
>

I think i agree with you: The template is instantiated, and so the rule doe=
s
not apply. Let's consider this:

template<typename T>
void f() { sizeof(T) == 0; }
int g() { return 1; }

int main() { int a[g()]; }

This can indeed never yield a valid specialization, but the template still
is semantically correct so should parse (so this is different from the "+;"
and "hello;" stuff above that, IMHO, depend on the interpretation of the
standard reader). So the rule certainly applies, and then 1.4/2 says

"=97 If a program contains a violation of a rule for which no diagnostic is
required, this International Standard places no requirement on
implementations with respect to that program."

This is what effectively yields undefined behavior, i think.

>> Or is the wording about "no diagnostic required" not actually aimed to
> allow
>> to effectively yield undefined behavior? That's the major part that
>> cause=
> s
>> confusion to me. Because as far as i know, the microsoft compiler does
> this
>> "skip from { to }" thingy, and i heard that that is non-conformant. But
>> i=
> f
>> the standard grants them to accept the above code when read narrowly,
>> shouldn't MSVC be all-right doing that?
>
> But the standard gives no freedom to let above violation of the rules
> undiagnosed, so this is mood and it doesn't prevent the compiler XYZ
> from being buggy/non-conforming.
>
>> I mean, i see that the intention of the spec is to just let them go with
> the
>> ill-formed template, but require a diagnostic at instantiation. But to
>> th=
> e

>> letter of the Standard, i see it allowing to go without any diagnostic a=
t
>> all. I think the note should be normative. Or am i just missing somethin=


g
>> really hard?
>
> Let me say it differently: I cannot read your interpretation in the
> standard wording. The above quoted sentence is a normative
> sentence and is restricted to (a) template definitions, which are
> (b) not yet instantiated.

If we interpret it as "not yet" instantiated, then my first example would
have violated the rule for which no diagnostic is required. But i
interpreted you that you said that the rule does not apply, because the
template is instantiated at some point in the TU (and then a diagnostic
should appear - since the exact point where the diangnostic appears isn't
important, it doesn't matter whether the illformed template definition is
diagnosed right away or at instantiation - this is not influenced by the
rule in question). This statement reads as if you say that the rule applies
because the template is "not yet" instantiated at that point in the TU.

=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D

unread,
Apr 1, 2010, 1:51:24 PM4/1/10
to

The premise is wrong. The compiler is allowed to /guess/ in
this particular situation that

template<typename T>
void f(T t) {

/token-soup/
}

*could* be valid declaration. Ill-formed code within the sandbox
of an non-instantiated template definition doesn't make the
whole template definition well-formed.

> For each given program there are 3 mutually exclusive options:
> 1) the standard requires the ill-formed program to be diagnosed;

We have several rules where the standard does not require
a diagnostic, and this case is one of them.

> 2) the standard does not require the ill-formed to be diagnosed (in
> this case the behavior is undefined);

We meet here [intro.compliance]/2, bullet 3, yes.
On the one side, "undefined behaviour" is a fall-back wording
for the standard for *everything* that is not ruled. On the other
side, undefined behaviour is a runtime quality, no compile-time
quality.

In your example below, repeated in simplified form here:

template<class>
struct X { /token-soup/ };

int main() {}

I see nothing that that leads to such a undefined behavior. We
can go further and discuss variations of this, starting with (a):

template<class>
struct X { /token-soup/ };

int main() {
X<int> x;
}

Now the template X becomes instantiated and the compiler is required
to produce a diagnostic. But considering (b):

template<class>
struct X { /token-soup/ };

int main() {
X<int>* x;
}

there is no such requirement, but I still don't see a reason for
undefined behavior, because we could construct a similar
program (b2)

struct X; // incomplete

int main() {
X* x;
}

where the situation is comparable and that demonstrates that
{ /token-soup/ } doesn't change the meaning of the program.

I don't see a defect here. You could say that the situation
is unsatisfactory, but we have several others too, depending
on the view-point of the reporter, e.g. (based on N3090)
[basic.scope.class]/1 bullet 3, [basic.link]/11, or
[stmt.ambig]/3. But the bare existence of these isn't
sufficient as a proof that this is an inherent defect in the
standard.

If you want this rule to be changed, it would be required
to proof that the particular rule is not used by any
compiler or that it creates a particular language defect.
But I don't think we can reasonably discuss the latter
without a concrete example.

> 3) the standard has no strict answer about whether it requires ill-
> formed program to be diagnosed (in this case the standard has a
> defect).

It would be interesting to discuss a particular example, where
you could proof that. I don't think that it is sufficient to use
logical deduction from first principles, because the standard
does not require that a compiler has to perform such a logical
proof. The compiler will use some heuristics that might or
might not be wrong. If it is wrong, the

a) compiler has a bug or
b) the diagnostic may be misleading,
c) the standard has a defect.

Neither of the properties (a) and (b) are ruled by the standard,
for (c) we need an example to exclude the other choices.

> Given the following program
>
> template <class T>
> struct X
> {
> {
> } // is end?
> {
> {
> }; // is end?
> }; // is end?
>
> int main()
> {
> }
>
> what the standard/draft says about whether the diagnostic is required?

I say, that no diagnostic is required here, until you
find another special rule in the standard that refines
the above quoted one ;-)
I also won't exclude the possibility that for technical
reasons (depending on implementation details that
might or might not be true for basically every C++
compiler), every compiler has to diagnose this, but
such discussions are out of the scope of the standard
and should better be proceeded in another newsgroup
that concentrate on particular compiler details, unless
you find a particular case where a problem arises
that must be based on a defect in the standard. I
assume that providing such an example will be hard,
because the standard is intentionally fuzzy here
to give wiggle room for different parsing techniques.

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use

mailto:std...@netlab.cs.rpi.edu<std-c%2B%2...@netlab.cs.rpi.edu>

Johannes Schaub (litb)

unread,
Apr 2, 2010, 1:34:26 PM4/2/10
to
=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D wrote:

"If no valid specialization can be generated for a template de=EF=AC=81niti=
on, ...".

The premise is that we have a template definition. The Standard does not
state in that paragraph what you write. This is the intent, but the intent
is not reflected by that paragraph. As Nikolay said, to be a template
definition, it must first parse. The Standard has no such notion of a
"sandbox" or something like that, as far as i know. Templates are not
macros.

>> For each given program there are 3 mutually exclusive options:
>> 1) the standard requires the ill-formed program to be diagnosed;
>
> We have several rules where the standard does not require
> a diagnostic, and this case is one of them.
>
>> 2) the standard does not require the ill-formed to be diagnosed (in
>> this case the behavior is undefined);
>
> We meet here [intro.compliance]/2, bullet 3, yes.
> On the one side, "undefined behaviour" is a fall-back wording
> for the standard for *everything* that is not ruled. On the other
> side, undefined behaviour is a runtime quality, no compile-time
> quality.
>

That's a common misconception. Undefined behavior happens likewise at
compile time. Unbound template instantiation yields undefined behavior as
well as producing an universal character name when splicing lines, defining
a class differently in different translation units and putting an escape
sequence into a source-file name inside a "#include".

Two cases of undefined behavior exist: If you violate any rule for which no
diagnostic is required at compile time, the standard does not require a
diagnostic anymore (actually, no requirements are stated at all anymore
then).

And if at runtime an execution sequence that the corresponding abstract
machine has contains undefined behavior, no requirements are stated anymore
to the implementation running that program (with that input). The undefined
behavior is not even required to be hit - it just has to occur in a
*possible* execution path that is possible by the mere fact that whether or
not the path is taken is unspecified. (as in reading different members of
unions which could possibly trap - one can't know from a theoretical point
of view, since while alignment is implementation defined, the value
representation is not and so introduces non-determinism).

> In your example below, repeated in simplified form here:
>
> template<class>
> struct X { /token-soup/ };
>
> int main() {}
>
> I see nothing that that leads to such a undefined behavior.
>

If your reasoning is that the template is "ill-formed; no diagnostic
required", this is effectively undefined behavior, and the compiler might
interpret "int main() { }" as a command for shutting down the OS.

> But considering (b):
>
> template<class>
> struct X { /token-soup/ };
>
> int main() {
> X<int>* x;
> }
>
> there is no such requirement, but I still don't see a reason for
> undefined behavior, because we could construct a similar
> program (b2)
>
> struct X; // incomplete
>
> int main() {
> X* x;
> }
>
> where the situation is comparable and that demonstrates that
> { /token-soup/ } doesn't change the meaning of the program.
>

I don't don't follow that logic. The last example is perfectly valid, and i=
s
not comparable to your previous code. It merely shows that "X" is not
instantiated - however to be undefined behavior, the template does not have
to be instantiated, because then the rule would not apply.

So given all that is written in that paragraph, if the nonnormative note an=
d
examples are erased, if i were to write an implementation i would interpret
it like:

// Oops, must be diagnosed here! Syntax error. We can't know what it is.
template<typename T> void f() { +; }

// oops, must be diagnosed here!
// or later!?
template<typename T> void f() { huh; }

The confusion here is that the template is ill-formed already when doing
name lookup for "huh". Since it's nondependent, we don't have to instantiat=
e
the template to see it's ill-formed. The paragraph sounds unclear about wha=
t
to do in this instance.

// alright, parses OK and semantics are fine.
// however, no valid specialization can be instantiated, so
// the template definition is ill-formed, no diagnostic required.


template<typename T>
void f() {

// forgot to put this into a array declarator in my other post.
// sorry dude!
int a[sizeof(T) == 0];
}

This last example is the only one i clearly see the paragraph applies to. I
would conclude that no diagnostic is required because it's difficult to
deduce that this will never yield a valid specialization. I would never hav=
e
the idea that it is because of a "macro like" interpretation of templates a=
t
all!

As the freshly baken compiler writer, i would say

"hah, no diagnostic required, so i just throw away that rule, since it
grants me to ignore it.".

So in effect, the whole paragraph does say nothing essential at all, i
think. Instead, it makes the last example effectively to have undefined
behavior, which i think isn't good.

Nikolay Ivchenkov

unread,
Apr 2, 2010, 1:35:38 PM4/2/10
to
On 1 Apr, 21:51, Daniel_Krugler <daniel.krueg...@googlemail.c=.om>
wrote:

> On Apr 1, 6:49 am, Nikolay Ivchenkov <ts...@mail.ru> wrote:
> > According to your reasoning, when the compiler does not diagnose the
> > following
>
> > template<typename T>
> > void f(T t) { +; }
>
> > it must know that this construct is a declaration. So, is it a
> > declaration, and why exactly?
>
> The premise is wrong. The compiler is allowed to /guess/ in
> this particular situation that
>
> template<typename T>
> void f(T t) {
> /token-soup/
>
> }

Where does the normative text contain a specification of "token-soup"?
And where the normative part of the standard allows such behavior of a
compiler?

The grammar might be defined as follows:

template-declaration:
template < template-parameter-list > potential-declaration

potential-declaration:
potential-function-definition
....

potential-function-definition:
attribute-specifier opt decl-specifier-seq opt declarator
potential-function-body
attribute-specifier opt decl-specifier-seq opt declarator =
default ;
attribute-specifier opt decl-specifier-seq opt declarator =
delete ;

potential-function-body:
potential-ctor-initializer opt potential-compound-statement
potential-function-try-block

potential-compound-statement:
token-soup

token-soup:
....

Such a grammar could allow your interpretation, but the existing
grammar and respective specification don't, IMO.

> > For each given program there are 3 mutually exclusive options:

*Amendment: For each given ill-formed program...

> > 1) the standard requires the ill-formed program to be diagnosed;
>
> We have several rules where the standard does not require
> a diagnostic, and this case is one of them.

OK, suppose a compiler is allowed to consider

template <class T>
void f(T t)
{
token-soup
}

as potential template definition where the end of the "token-soup" is
unspecified. Having the following program

#include <iostream>

template <class T>
void f(T t)
{
+;
}

void f(bool b)
{
} // could be end of the template definition?

void f(char const *s)
{
std::cout << s;
}

int main()
{
f(0); // should be ambiguous
}

may a compiler interpret the following sequence

+;
}

void f(bool b)
{

as "token-soup", compile the program successfully and call f(char
const *s) in the main function? Please, note: I am talking about
standard-conformance, not about existing implementations.

> On the other
> side, undefined behaviour is a runtime quality, no compile-time
> quality.

I don't think so. First, the informative text in the definition of
"undefined behavior" says:

"permissible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of a
diagnostic message)."

Second, N3092 directly uses the term "undefined behavior" with regard
to translation phases too. For example:

[lex.phases]/2:
"If, as a result, a character sequence that matches the syntax of a
universal-character-name is produced, the behavior is undefined."

[basic.def.odr]/5 - the last sentence:
"If the definitions of D do not satisfy these requirements, then the
behavior is undefined."

[expr.unary.op]/5:
"The address of an object of incomplete type can be taken, but if the
complete type of that object is a class type that declares operator&()
as a member function, then the behavior is undefined (and no
diagnostic is required)."

[temp.inst]/14:
"The result of an infinite recursion in instantiation is undefined."

[cpp.concat]/3:
"Placemarker preprocessing tokens are handled specially: concatenation
of two placemarkers results in a single placemarker preprocessing
token, and concatenation of a placemarker with a non-placemarker
preprocessing token results in the non-placemarker preprocessing
token. If the result is not a valid preprocessing token, the behavior
is undefined."

> > 3) the standard has no strict answer about whether it requires ill-
> > formed program to be diagnosed (in this case the standard has a
> > defect).
>
> It would be interesting to discuss a particular example, where
> you could proof that.

You should disprove the first option before.

Nikolay Ivchenkov

unread,
Apr 4, 2010, 2:02:55 PM4/4/10
to
On 2 Apr, 21:34, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:

> Daniel_Krugler wrote:
> > On Apr 1, 6:49 am, Nikolay Ivchenkov <ts...@mail.ru> wrote:
> >> According to your reasoning, when the compiler does not diagnose the
> >> following
>
> >> template<typename T>
> >> void f(T t) { +; }
>
> >> it must know that this construct is a declaration. So, is it a
> >> declaration, and why exactly?
>
> > The premise is wrong. The compiler is allowed to /guess/ in
> > this particular situation that
>
> > template<typename T>
> > void f(T t) {
> > /token-soup/
> > }
>
> > *could* be valid declaration. Ill-formed code within the sandbox
> > of an non-instantiated template definition doesn't make the
> > whole template definition well-formed.
>
> "If no valid specialization can be generated for a template de=EF=AC=81niti=
> on, ...".
>
> The premise is that we have a template definition. The Standard does not
> state in that paragraph what you write. This is the intent, but the intent
> is not reflected by that paragraph. As Nikolay said, to be a template
> definition, it must first parse. The Standard has no such notion of a
> "sandbox" or something like that, as far as i know. Templates are not
> macros.

Exactly. I will try to explain our point of view in other words.

A declaration may be semantically incorrect. For example, the
following construct

void f()
{
return 0;
}

syntactically matches the declaration (and can be considered to be
declaration), but such declaration is ill-formed according to semantic
rules. However, a declaration cannot be syntactically incorrect,
because it is syntactically correct by definition: a sequence of
tokens can be considered to be declaration only if the sequence
matches the syntactic pattern specified for declarations (using
disambiguation rules when it is necessary). Thus, the following
construct

void f()
{
+;
}

is not a declaration because the sequence of tokens "void f ( )
{ + ; }" does not match the declaration syntax (note: "+ ;" does not
match statement-seq syntax).

Since every template definition is a declaration, there can be no
syntactically incorrect template definitions. In particular, the
"declaration" part of the template-declaration pattern cannot be
syntactically incorrect.

template <class T> void f() { +; }

Here "+;" is not a statement-seq, "{ +; }" is not a compound-
statement, "void f() { +; }" is not a declaration, and "template
<class T> void f() { +; }" is not a declaration nor a template
definition. In contrast,

template <class T>
void f()
{ return 0; }

is a template definition that is ill-formed according to semantic
rules. The rule "If no valid specialization can be generated for a


template definition, and that template is not instantiated, the

template definition is ill-formed, no diagnostic required" can only be
applied to a construct that is syntactically resolved to a template
definition. Thus, we could apply this rule to the last example, but
not to the next to last example.

--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]

=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D

unread,
Apr 7, 2010, 1:20:23 PM4/7/10
to
On Apr 2, 7:34 pm, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
> state in that paragraph what you write. This is the intent, but the inten=

t
> is not reflected by that paragraph. As Nikolay said, to be a template
> definition, it must first parse. The Standard has no such notion of a
> "sandbox" or something like that, as far as i know. Templates are not
> macros.

I agree, my interpretations went too far. Nonetheless, the freedom
of the compiler is still restricted to non-instantiated templates and
at least a declaration must be possible. In e.g.

template <class T> +;

the requirement for a possible declaration is not satisfied and the
code is ill-formed in a way that must be diagnosed. I cannot read
your interpretation from the standard that a compiler may *not*
diagnose this:

template <class T> +;

> unions which could possibly trap - one can't know from a theoretical poin=


t
> of view, since while alignment is implementation defined, the value
> representation is not and so introduces non-determinism).

Yes, you are correct, I was way off here.

> > In your example below, repeated in simplified form here:
>
> > template<class>
> > struct X { /token-soup/ };
>
> > int main() {}
>
> > I see nothing that that leads to such a undefined behavior.
>
> If your reasoning is that the template is "ill-formed; no diagnostic
> required", this is effectively undefined behavior, and the compiler might
> interpret "int main() { }" as a command for shutting down the OS.

I agree.

> I don't don't follow that logic. The last example is perfectly valid, and
i=
> s
> not comparable to your previous code. It merely shows that "X" is not
> instantiated - however to be undefined behavior, the template does not
have
> to be instantiated, because then the rule would not apply.

Correct.

> So given all that is written in that paragraph, if the nonnormative note
an=
> d
> examples are erased, if i were to write an implementation i would
interpret
> it like:
>
> // Oops, must be diagnosed here! Syntax error. We can't know what it is.
> template<typename T> void f() { +; }

This must not be diagnosed if not instantiated, but yes, doing so, is
OK.

> // oops, must be diagnosed here!
> // or later!?
> template<typename T> void f() { huh; }
>
> The confusion here is that the template is ill-formed already when doing
> name lookup for "huh". Since it's nondependent, we don't have to
instantiat=
> e
> the template to see it's ill-formed. The paragraph sounds unclear about
wha=
> t
> to do in this instance.

There exists [temp.res]/9 which says what to do in this
situation. So, while your former example could be
diagnosed without any context available, this is not
true for this example. There may or not be any huh
available in this context.

> // alright, parses OK and semantics are fine.
> // however, no valid specialization can be instantiated, so
> // the template definition is ill-formed, no diagnostic required.
> template<typename T>
> void f() {
> // forgot to put this into a array declarator in my other post.
> // sorry dude!
> int a[sizeof(T) == 0];
> }

OK, I understand your example better, now.

> This last example is the only one i clearly see the paragraph applies to.
I
> would conclude that no diagnostic is required because it's difficult to
> deduce that this will never yield a valid specialization. I would never
hav=
> e
> the idea that it is because of a "macro like" interpretation of templates
a=
> t
> all!

I agree, but the problematic situation occurs only, if f is not
instantiated.

> As the freshly baken compiler writer, i would say
>
> "hah, no diagnostic required, so i just throw away that rule, since it
> grants me to ignore it.".
>
> So in effect, the whole paragraph does say nothing essential at all, i
> think. Instead, it makes the last example effectively to have undefined
> behavior, which i think isn't good.

It does indeed so, if in the last example f is not instantiated.
I still don't see why the paragraph doesn't say anything
essential, it is intended as a hint for an implementation, and
it is a warning for a programmer. [Obviously I didn't have the
feeling that I was warned enough ;-)]

I'm not sure whether your example is intended to realize some
useful or not. If intended to do something useful, I suggest
to follow this approach:

template<typename>
struct always_false {
static const bool value = false;
};

template<typename T>
void f() {

static_assert(always_false<T>::value, "Instantiating f is not
allowed");
}

This function template will always be ill-formed on instantiation,
unless someone provides a specialization for always_false
which has a static member value that evaluates to true, so it
does not belong to the potential undefined behavior domain.

HTH & Greetings from Bremen,

Daniel Kr=FCgler


=3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D

unread,
Apr 7, 2010, 1:38:30 PM4/7/10
to
On Apr 1, 7:51 pm, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:

> Let's consider this:
>
> template<typename T>
> void f() { sizeof(T) == 0; }
> int g() { return 1; }
>
> int main() { int a[g()]; }
>
> This can indeed never yield a valid specialization,

Why? There exist a lot of types for which the template itself
could be successfully instantiated.

> but the template still
> is semantically correct so should parse (so this is different from the
"+;"
> and "hello;" stuff above that, IMHO, depend on the interpretation of the
> standard reader). So the rule certainly applies, and then 1.4/2 says
>

> "=97 If a program contains a violation of a rule for which no diagnosti=
c


is
> required, this International Standard places no requirement on
> implementations with respect to that program."
>
> This is what effectively yields undefined behavior, i think.

I assume you didn't mean what you say or I didn't understand
your statement. I assume you either have above example with
function template f being defined to

template<typename T>
void f() { return sizeof(T) == 0; }

or defined to

template<typename T>
void f() { +; }

in your mind. I agree that both variants produce a program with
undefined
behavior.

> >> Or is the wording about "no diagnostic required" not actually aimed to
> > allow
> >> to effectively yield undefined behavior? That's the major part that
> >> cause=
> > s
> >> confusion to me. Because as far as i know, the microsoft compiler does
> > this

> >> "skip from { to }" thingy, and i heard that that is non-conformant. Bu=

Your first example was this:

template<typename T>
void f(T t) { +; }

which is no complete program. But within a program and not being
instantiated
anywhere this causes undefined behavior in correction to my first
reply to Nicolay
see further details in my reply on that subthread.

> But i
> interpreted you that you said that the rule does not apply, because the
> template is instantiated at some point in the TU (and then a diagnostic
> should appear - since the exact point where the diangnostic appears isn't
> important, it doesn't matter whether the illformed template definition is
> diagnosed right away or at instantiation - this is not influenced by the
> rule in question). This statement reads as if you say that the rule
applies
> because the template is "not yet" instantiated at that point in the TU.

I rethought your last example assumed to be as quoted here:

template<typename T>
void f() { return sizeof(T) == 0; }
int g() { return 1; }

int main() { int a[g()]; }

and I agree with you that by a strict reading of the standard this
program causes undefined behavior and may not produce any
diagnostic. It could produce an executable with no requirements
on what this executable does.

This is in fact not different than a program that is produced from
the following two TU's:

#TU1:

int b;

#TU2:

int b;

int g() { return 1; }

int main() { int a[g()]; }

Note that b is not even used, but the program still causes
undefined behavior none-the-less because of the violation
of the ODR.

I do not know of any compiler that does *not* diagnose the
ill-formed code in main in either of these programs and I
don't think that any serious compiler does so (Yes, the
legends remark of earlier versions of gcc [I believe] that
would have done exactly this and would have started a
game if the executable were started).

HTH & Greetings from Bremen,

Daniel Kr=FCgler


0 new messages