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

Improved error messages for template code

1 view
Skip to first unread message

Brian Parker

unread,
Jan 21, 1999, 3:00:00 AM1/21/99
to
I have some ideas on the subject of improving the display of template
instantiation errors for library code and would be interested in any
feedback on them. If the idea is not shot down completely I may try
implementing it in the ecgs sources.

The problem, as is well known, is that if a user of a library instantiates a
library template class or function with a type that does not fulfill the
expected requirements typically a compile-time error is generated deep
within the bowels of the library code which generates errors which are less
than perspicuous
e.g. in ecgs1.1 the following code sample -

template<typename T>
void func2(const T& t){
set<complex<double> > m;

m.insert(t);
}

template<typename T>
void func1(const T& t){
func2(t);
}

//...

func1(complex<double>(1.0, 1.0));

gives something like-

c:\\develfiles\\ecgs11\\lib\\gcc-lib\\i386-mingw32\\egcs-2.91.57\\..\\..\\..
\\..
\\include\\g++\\stl_function.h: In method `bool less<complex<double>
>::operator
()<complex<double>>(const class complex<double> &, const class
complex<double>
&) const':
c:\\develfiles\\ecgs11\\lib\\gcc-lib\\i386-mingw32\\egcs-2.91.57\\..\\..\\..
\\..
\\include\\g++\\stl_tree.h:731: instantiated from
`rb_tree<complex<double>,com
plex<double>,identity<complex<double> >,less<complex<double>
>,__default_alloc_t
emplate<false,0> >::insert_unique<complex<double>, complex<double>,
identity<com
plex<double> >, less<complex<double> >, alloc>(const complex<double> &)'
c:\\develfiles\\ecgs11\\lib\\gcc-lib\\i386-mingw32\\egcs-2.91.57\\..\\..\\..
\\..
\\include\\g++\\stl_set.h:116: instantiated from
`set<complex<double>,less<com
plex<double> >,__default_alloc_template<false,0> >::insert<complex<double>,
less
<complex<double> >, alloc>(const complex<double> &)'
pd_debug_test.cpp:46: instantiated from `func2<complex<double>>(const
complex<
double> &)'
pd_debug_test.cpp:107: instantiated from here
c:\\develfiles\\ecgs11\\lib\\gcc-lib\\i386-mingw32\\egcs-2.91.57\\..\\..\\..
\\..
\\include\\g++\\stl_function.h:100: no match for `const complex<double> & <
cons
t complex<double> &'


I suggest that a simple #pragma could do much to alleviate this problem as
follows:

The pragma would be of the form-

#pragma template_error "Error in SGI STL library: template type T must be
Comparable... etc"

// STL functions and classes defined here.

#pragma template_error off

The meaning of this is that *any* compile-time error occurring between the
matching #pragmas (no matter how deeply it occurs within a nested function
call) would be replaced by the text of the #pragma, and possibly the exact
error message (without file or line information) would follow,
e.g. the error message from the example above would become-

Error in SGI STL library: template type T must be Comparable.
Error was "no match for `const complex<double> & < const complex<double> &'"
pd_debug_test.cpp:46: instantiated from `func2<complex<double>>(const
complex<
double> &)'
pd_debug_test.cpp:107: instantiated from here

This immediately indicates the source of the problem to the library user,
who can then investigate why their type T doesn't meet the library's
requirements.

Some issues are:
(1) This presumes that any compile-time error is due to a misuse on the part
of the library user- this is reasonable for debugged library code.

(2) The pragma as specified can't give separate error messages for different
constraint violations. I originally considered a syntax whereby individual
error numbers could be mapped to different messages but I can't see any way
to make that portable. In any case I think that it is overkill- a single
message indicating that the problem is with the use of a particular library
function should be enough, and showing the final error message should
indicate the particular constraint that was violated. If not, a compiler
switch could disable the pragma and allow the full nested error message (at
least in this case the user will know what they are looking for).

(3) This pragma could be used to give more or less detailed messages- at one
extreme an entire library could be wrapped in a pair of pragmas that just
indicate the library that caused the error, or, at the other extreme,
individual functions could be wrapped to give more detailed diagnostics.

(4) Note that the pragma is nested i.e. the outermost pragma pair generates
the final compiler error message.

I think that this would be a fairly simple feature to add to a compiler and
would increase the usability of library code. Ideally it would become a
standard pragma, but even if a compiler just ignored it, it would be, I
think, useful internal documentation.

Also, as a trivial change on the same subject, IMO a compiler switch to
optionally hide namespace qualifiers (and perhaps, also, template
parameters) from all error messages would be a useful feature to remove
clutter.

Anyway, what do you'all think?

,Brian Parker
(bpa...@uq.net.au)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]

Scott Meyers

unread,
Jan 24, 1999, 3:00:00 AM1/24/99
to
Brian Parker <bpa...@uq.net.au> wrote in message news:786tnl$bqm$1...@bunyip.cc.uq.edu.au...

>I have some ideas on the subject of improving the display of template
>instantiation errors for library code and would be interested in any
>feedback on them.

A couple of additional ideas were suggested to me at a conference recently:
- When reporting errors during template instantiation, use a typedef
name if the client code did
- Omit defaulted parameters in diagnostics

For example, if the client code says

typedef basic_string<BLORP> BlorpString;

BlorpString s;

and there's an error during instantiation of basic_string<BLORP>, the
diagnostic would refer to BlorpString instead of to
basic_string<BLORP, char_traits<BLORP>, allocator<BLORP>.

Scott

Scott Meyers, Ph.D. Voice: 503/638-6028
Author: Effective C++ CD Fax: 503/638-6614
Effective C++ Email: sme...@aristeia.com
More Effective C++ WWW: http://www.aristeia.com/

All...@my-dejanews.com

unread,
Jan 24, 1999, 3:00:00 AM1/24/99
to
In article <786tnl$bqm$1...@bunyip.cc.uq.edu.au>,

"Brian Parker" <bpa...@uq.net.au> wrote:
> I have some ideas on the subject of improving the display of template
> instantiation errors for library code and would be interested in any
> feedback on them. If the idea is not shot down completely I may try
> implementing it in the ecgs sources.

The idea of improving template instantiation for library code is
excellent one. By definition, this is a quality of implementation
issue, independant of the C++ standard.

> I suggest that a simple #pragma could do much to alleviate this problem as
> follows:
>
> The pragma would be of the form-
>
> #pragma template_error "Error in SGI STL library: template type T must be
> Comparable... etc"
>
> // STL functions and classes defined here.
>
> #pragma template_error off

Looks as if you're changing the error message text to "off". Nesting
could also be useful. May I suggest an alternate syntax?
#pragma template_error(push,"STL error in sort: type T must be Comparable")
and
#pragma template_error(pop)

> The meaning of this is that *any* compile-time error occurring between the
> matching #pragmas (no matter how deeply it occurs within a nested function
> call) would be replaced by the text of the #pragma, and possibly the exact
> error message (without file or line information) would follow,
> e.g. the error message from the example above would become-
>
> Error in SGI STL library: template type T must be Comparable.
> Error was "no match for `const complex<double> & < const complex<double> &'"
> pd_debug_test.cpp:46: instantiated from `func2<complex<double>>(const
> complex<
> double> &)'
> pd_debug_test.cpp:107: instantiated from here
>
> This immediately indicates the source of the problem to the library user,
> who can then investigate why their type T doesn't meet the library's
> requirements.

Bravo.

> Some issues are:
> (1) This presumes that any compile-time error is due to a misuse on the part
> of the library user- this is reasonable for debugged library code.

It could also be used for any other debugged packages, including
third-party packages. That's why I'm thinking that the messages
should nest, although this might not be needed.

> (2) The pragma as specified can't give separate error messages for different
> constraint violations. I originally considered a syntax whereby individual
> error numbers could be mapped to different messages but I can't see any way
> to make that portable.

Don't worry about portability; the contents and semantics of #pragma
intentionally are not covered by the standard. Also, this wouldn't
require or even allow changes in conforming code, so it's not a
standards issue.

I don't use ecgs, but presumably if one c++ compiler solved this thorny
issue then other compiler vendors would feel pressure to follow suit.

> In any case I think that it is overkill- a single
> message indicating that the problem is with the use of a particular library
> function should be enough, and showing the final error message should
> indicate the particular constraint that was violated.

Perhaps not. Are all errors of this type due to the same error?
If not, then the message may indicate the wrong constraint; for
beginners, the wrong error message is worse than a vague one
(i.e. "Error at line 20" is better than "Division by 0 at line 20"
unless there really is a division by 0 error).

> If not, a compiler
> switch could disable the pragma and allow the full nested error message (at
> least in this case the user will know what they are looking for).
>
> (3) This pragma could be used to give more or less detailed messages- at one
> extreme an entire library could be wrapped in a pair of pragmas that just
> indicate the library that caused the error, or, at the other extreme,
> individual functions could be wrapped to give more detailed diagnostics.

I would want the messages to be as specific as possible without
introducing the possibility of misleading error messages.

----
All...@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Siemel Naran

unread,
Jan 24, 1999, 3:00:00 AM1/24/99
to
On 21 Jan 99 19:35:41 GMT, Brian Parker <bpa...@uq.net.au> wrote:

> set<complex<double> > m;
> m.insert(t);

Inserting an element into 'm' makes use of operator<(T,T) for
T==complex<double>. There is no such operator.

The "instantiated from ..." lines are pretty much useless.
They essentially say that an error occurred while instantiating
'set::<T>::insert(...)'. They provide the context for the
error message -- ie, where the error message occurred.
The last line contains the real error message.
We should use the notation operator< as the '<' and '>' are confusing.

So the error message should be:

pd_debug_test.cpp:107: instantiation of 'std::map<T,Less,Alloc>::insert(
const T&)' with T==std::complex<double>, Less==default, Alloc==default.
$STL\stl_function.h:100: no match for 'operator<(const T&, const T&)'
with T==std::complex<double>.

>I suggest that a simple #pragma could do much to alleviate this problem as
>follows:

But what happens if the error is due to something other than the
#pragma. Now the words of the #pragma are misleading.

>(1) This presumes that any compile-time error is due to a misuse on the part
>of the library user- this is reasonable for debugged library code.

People might want to use these #pragma's in their own code.
And their own code might be far from flawless.


>(2) The pragma as specified can't give separate error messages for different
>constraint violations. I originally considered a syntax whereby individual
>error numbers could be mapped to different messages but I can't see any way
>to make that portable. In any case I think that it is overkill- a single
>message indicating that the problem is with the use of a particular library
>function should be enough, and showing the final error message should
>indicate the particular constraint that was violated. If not, a compiler
>switch could disable the pragma and allow the full nested error message (at
>least in this case the user will know what they are looking for).

OK.


>(3) This pragma could be used to give more or less detailed messages- at one
>extreme an entire library could be wrapped in a pair of pragmas that just
>indicate the library that caused the error, or, at the other extreme,
>individual functions could be wrapped to give more detailed diagnostics.
>
>(4) Note that the pragma is nested i.e. the outermost pragma pair generates
>the final compiler error message.

OK.


>Also, as a trivial change on the same subject, IMO a compiler switch to
>optionally hide namespace qualifiers (and perhaps, also, template
>parameters) from all error messages would be a useful feature to remove
>clutter.

One difficulty here is that you can hide the namespace name only if
the entity occurs in one namespace.

Instead of writing out template parameters or avoiding writing them
at all, write out the generic template parameters. This means that
you need to store the variable names when parsing the template. Eg,
template <class T, class allocator> class vector;
is normally stored as vector<class,class>. But it should be stored
as vector<class T, class allocator>. In the present scheme error
messages would say,
error in instantiating std::vector<complex<double>, std::allocator<double>>
But in the new scheme, the error messages say,
error in instantiating std::vector<T,allocator> with T==complex<double>
and allocator==std::allocator<double>

The error messages should also use typedefs. So if there is a typedef
ostream for basic_ostream<char,char_traits<char>>, the error message
should employ the name "ostream" rather than the name "basic_ostream
<char,char_traits<char>>".

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Brian Parker

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to
All...@my-dejanews.com wrote in message <78ac8l$59v$1...@nnrp1.dejanews.com>...
>...

>> #pragma template_error off
>
>Looks as if you're changing the error message text to "off". Nesting
>could also be useful. May I suggest an alternate syntax?
> #pragma template_error(push,"STL error in sort: type T must be
Comparable")
>and
> #pragma template_error(pop)
>...

>It could also be used for any other debugged packages, including
>third-party packages. That's why I'm thinking that the messages
>should nest, although this might not be needed.

Yes, the #pragmas will definitely need to nest so that only the outermost
one is displayed to the user (so any other library code used internally in
the implementation of a library is not shown to the user).

I agree that "push"/"pop" may be a better syntax- Visual C++ has nested
#pragmas using such a syntax.

>...


>Don't worry about portability; the contents and semantics of #pragma
>intentionally are not covered by the standard. Also, this wouldn't
>require or even allow changes in conforming code, so it's not a
>standards issue.


Ideally, I think, standardising it in the long term would be of benefit for
portable libraries; C9x has introduced the concept of standard #pragmas
(using a syntax like "#pragma stdc whatever").

>...


>> In any case I think that it is overkill- a single
>> message indicating that the problem is with the use of a particular
library
>> function should be enough, and showing the final error message should
>> indicate the particular constraint that was violated.
>

>Perhaps not. Are all errors of this type due to the same error?
>If not, then the message may indicate the wrong constraint; for
>beginners, the wrong error message is worse than a vague one
>(i.e. "Error at line 20" is better than "Division by 0 at line 20"
>unless there really is a division by 0 error).


Yes, I've gone off this idea a bit as it may lead to such incorrect
diagnostics- see the discussion in my reply to Siemel Naran for further
details.

Brian Parker

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to

Siemel Naran wrote in message ...
>...


>The "instantiated from ..." lines are pretty much useless.
>They essentially say that an error occurred while instantiating
>'set::<T>::insert(...)'. They provide the context for the
>error message -- ie, where the error message occurred.
>The last line contains the real error message.
>We should use the notation operator< as the '<' and '>' are confusing.
>
>So the error message should be:
>
>pd_debug_test.cpp:107: instantiation of 'std::map<T,Less,Alloc>::insert(
>const T&)' with T==std::complex<double>, Less==default, Alloc==default.
>$STL\stl_function.h:100: no match for 'operator<(const T&, const T&)'
>with T==std::complex<double>.


I think I like this... but just to clarify, you are still suggesting a
#pragma but without a text message, right? Otherwise how would the
implementation know that map::insert() is the distinguished function to
display to the user rather than, say, the failed rb_tree constructor? Also,
I find the "instantiated from" lines extremely useful for finding errors in
*non-library* template code, so some means to distinguish the two uses is
needed.

(Actually, to answer my own question- I wonder if having the compiler choose
the distinguished function as the first one in a new namespace, rather than
via a #pragma, would be a better solution, on the presumption that library
code will be wrapped in its own namespace... or is that too subtle).

With Scott Meyer's suggestion to elide the display of default template
arguments, the above error message becomes even simpler-

pd_debug_test.cpp:107: instantiation of 'std::map<T>::insert(
const T&)' with T==std::complex<double>.


$STL\stl_function.h:100: no match for 'operator<(const T&, const T&)'
with T==std::complex<double>.

Actually, making the text of the #pragma optional may still be useful for
third party libraries so that a very general message to identify the library
can be displayed. So the above message would become-

Error in template instantiation using SGI STL:
pd_debug_test.cpp:107: instantiation of 'sgi::map<T>::insert(
const T&)' with T==stl::complex<double>.


$STL\stl_function.h:100: no match for 'operator<(const T&, const T&)'
with T==std::complex<double>.

>>(1) This presumes that any compile-time error is due to a misuse on the


part
>>of the library user- this is reasonable for debugged library code.
>
>People might want to use these #pragma's in their own code.
>And their own code might be far from flawless.


Yes, I intended for the #pragma to be used in third-party libraries, but
you're right- the risk of an inaccurate message being displayed is probably
too high in the original formulation.

>>Also, as a trivial change on the same subject, IMO a compiler switch to
>>optionally hide namespace qualifiers (and perhaps, also, template
>>parameters) from all error messages would be a useful feature to remove
>>clutter.
>
>One difficulty here is that you can hide the namespace name only if
>the entity occurs in one namespace.


Yes, it could be ambiguous if several namespaces were used and hence would
not be the default display. My main use for this would be in deeply
recursive template code (e.g. using expression templates) where any
reduction in clutter would be a boon.

>
>Instead of writing out template parameters or avoiding writing them
>at all, write out the generic template parameters. This means that
>you need to store the variable names when parsing the template. Eg,
> template <class T, class allocator> class vector;
>is normally stored as vector<class,class>. But it should be stored
>as vector<class T, class allocator>. In the present scheme error
>messages would say,
> error in instantiating std::vector<complex<double>,
std::allocator<double>>
>But in the new scheme, the error messages say,
> error in instantiating std::vector<T,allocator> with T==complex<double>
> and allocator==std::allocator<double>


Yes, I really like this format (and it would, I think, be particularly good
for deeply nested templates).

>
>The error messages should also use typedefs. So if there is a typedef
>ostream for basic_ostream<char,char_traits<char>>, the error message
>should employ the name "ostream" rather than the name "basic_ostream
><char,char_traits<char>>".


Yes, absolutely.


I think this is getting close to a much more useful template error message
format. Any further comments anyone?

,Brian Parker.
(bpa...@uq.net.au)

Brian Parker

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to

Scott Meyers wrote in message ...
>...


>A couple of additional ideas were suggested to me at a conference recently:
> - When reporting errors during template instantiation, use a typedef
> name if the client code did
> - Omit defaulted parameters in diagnostics

>...

Yes, those are both excellent suggestions, particularly not showing the
default template parameters- one need never be bothered by an Allocator
again.

(Though I'll have to see how difficult it is to implement the typedef one in
ECGS.)

,Brian Parker
(bpa...@uq.net.au)

Andrei Alexandrescu

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to

Scott Meyers wrote in message ...
>A couple of additional ideas were suggested to me at a conference recently:
> - When reporting errors during template instantiation, use a typedef
> name if the client code did
> - Omit defaulted parameters in diagnostics
>
>For example, if the client code says
>
> typedef basic_string<BLORP> BlorpString;
>
> BlorpString s;
>
>and there's an error during instantiation of basic_string<BLORP>, the
>diagnostic would refer to BlorpString instead of to
>basic_string<BLORP, char_traits<BLORP>, allocator<BLORP>.


After that discussion I followed Scott's advice and wrote an open letter
about it, addressed to compiler writers. It's scheduled to appear in C/C++
Users Journal in March.

Together with it there are three interesting answers from three compiler
writers: Steve Clamage (Sun), John Spicer (EDG), and Jonathan Caves
(Microsoft). Brian -- you may want to take a look at it. I hope you'll also
send a follow-up.

There's also a third thing: for templates instantiated with non-type
parameters, use symbolic names instead of constants.

All these are subject to compiler settings, as in some cases the bare-metal
types and values might be needed.

Andrei

Andrei Alexandrescu

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to
Siemel Naran wrote in message ...
[ultra-long error messages snipped]

>The "instantiated from ..." lines are pretty much useless.
>They essentially say that an error occurred while instantiating
>'set::<T>::insert(...)'. They provide the context for the
>error message -- ie, where the error message occurred.

The "instantiated from" error messages are sometimes valuable. When I once
ported code from a compiler to another, I had errors in the standard
headers, and I didn't have any clue where the problem actually is.

The only way to solve it was to comment in and out code with "#if 0" in kind
of a binary search... :o)

Andrei

Siemel Naran

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to

On 25 Jan 1999 16:48:53 GMT, Brian Parker <bpa...@uq.net.au> wrote:
>Siemel Naran wrote in message ...

>>So the error message should be:
>>
>>pd_debug_test.cpp:107: instantiation of 'std::map<T,Less,Alloc>::insert(
>>const T&)' with T==std::complex<double>, Less==default, Alloc==default.
>>$STL\stl_function.h:100: no match for 'operator<(const T&, const T&)'
>>with T==std::complex<double>.

>I think I like this... but just to clarify, you are still suggesting a


>#pragma but without a text message, right? Otherwise how would the
>implementation know that map::insert() is the distinguished function to
>display to the user rather than, say, the failed rb_tree constructor? Also,
>I find the "instantiated from" lines extremely useful for finding errors in
>*non-library* template code, so some means to distinguish the two uses is
>needed.

In the "instantiated from ..." lines, map::insert is the last line
that appears (I think). Something like this,
in rbtree
instantiated from siuysdfjg
instantiated from adslugfaysdg
instantiated from map.insert(const T&)
That's why the #pragma is not necessary.

>With Scott Meyer's suggestion to elide the display of default template
>arguments, the above error message becomes even simpler-

Cool. Technically, it's not valid either to omit default parameters
as there might be new default parameters. This may be good in a .cc
file.

// Template.h
template <class T1, class T2=T1> class Template { ... };

// File.c
#include "Template.h"
template <class T1=int, class T2> class Template;
void f() { Template<> t; }


>Actually, making the text of the #pragma optional may still be useful for
>third party libraries so that a very general message to identify the library
>can be displayed. So the above message would become-
>
>Error in template instantiation using SGI STL:
>pd_debug_test.cpp:107: instantiation of 'sgi::map<T>::insert(
>const T&)' with T==stl::complex<double>.

>$STL\stl_function.h:100: no match for 'operator<(const T&, const T&)'
>with T==std::complex<double>.

OK. But the compiler could do this too. If the file is in
"/usr/include/SGI", then the first line


Error in template instantiation using SGI STL

follows. Or maybe we read a comment at the top of the file
$STL\stl_function.h. Eg, my files begin like this
// filename.c
// by Siemel Naran
The less reliance on #pragma's, the better, as it frees the
author from writing these pragmas.

>>People might want to use these #pragma's in their own code.
>>And their own code might be far from flawless.
>

>Yes, I intended for the #pragma to be used in third-party libraries, but
>you're right- the risk of an inaccurate message being displayed is probably
>too high in the original formulation.

>>One difficulty here is that you can hide the namespace name only if
>>the entity occurs in one namespace.
>

>Yes, it could be ambiguous if several namespaces were used and hence would
>not be the default display. My main use for this would be in deeply
>recursive template code (e.g. using expression templates) where any
>reduction in clutter would be a boon.

Yes, the technical point is pretty useless in most cases, because
people will be able to figure out what was meant.


>Yes, I really like this format (and it would, I think, be particularly good
>for deeply nested templates).

Check out the error messages from a compiler like como (which
is an EDG compiler).


>>The error messages should also use typedefs. So if there is a typedef
>>ostream for basic_ostream<char,char_traits<char>>, the error message
>>should employ the name "ostream" rather than the name "basic_ostream
>><char,char_traits<char>>".
>

>Yes, absolutely.

But this is not so easy to implement.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Andrei Alexandrescu

unread,
Jan 25, 1999, 3:00:00 AM1/25/99
to

Brian Parker wrote in message <78ge28$hr9$1...@bunyip.cc.uq.edu.au>...
[snip]

>I think this is getting close to a much more useful template error message
>format. Any further comments anyone?


Brian,

No matter what, the nicest thing would be to have means for "smart" error
messages that apply not only to the standard library, but also to client
code and other libraries. The techniques should be general enough.

Besides, I think the point of instantiation stack should also be displayed.

There is a very subtle aspect about errors in C++. There are errors that
don't say a thing about their intention. For instance let's take the
static_checker class (posted by someone a while ago):

template <bool> class static_checker;
template <> static_checker<true> {};

The purpose is to do something like:

static_checker<sizeof(int) == sizeof(long)> dummy;

and to have a compile-time error if that's not the case. However, the error
text reads something like:

"Use of undefined class static_checker<false>"

instead of:

"Compile-time assumption failed: 'sizeof(int) == sizeof(long)' is false"

It would be great if you can achieve this with pragmas. Wow! Can't believe
that I could actually have such a great compiler. Any ideas?

Andrei

Brian Parker

unread,
Jan 26, 1999, 3:00:00 AM1/26/99
to

Andrei Alexandrescu wrote in message <36ac9...@10.1.1.65>...
>...


>The "instantiated from" error messages are sometimes valuable. When I once
>ported code from a compiler to another, I had errors in the standard
>headers, and I didn't have any clue where the problem actually is.


Yes, I'm a big fan of them too. They were introduced in Visual C++ 6 and
there it is a boon to be able to click on each "instantiated from" and walk
up the code (although they are undoubtedly less useful without good IDE
support).

,Brian Parker
(bpa...@uq.net.au)

Brian Parker

unread,
Jan 26, 1999, 3:00:00 AM1/26/99
to

Siemel Naran wrote in message ...

>...


>In the "instantiated from ..." lines, map::insert is the last line
>that appears (I think). Something like this,
> in rbtree
> instantiated from siuysdfjg
> instantiated from adslugfaysdg
> instantiated from map.insert(const T&)
>That's why the #pragma is not necessary.


OK. This is not quite what I was hoping to achieve; I only want to hide the
instantiation stack when the error is deep within library code- displaying
it in this case is meaningless to the user, but for normal user code I want
to show it as normal (with the sundry improvements suggested in this
thread).

One alternative to using pragmas would be to allow the library namespaces to
be specified on the command line or in an .rc file (possibly with a textual
annotation) and then errors occurring in those namespaces would be treated
as library errors.
Or maybe a #pragma with the same effect would still be useful- e.g.

#pragma library_namespace my_library_namespace "Error in My Library"
namespace my_library_namespace {
//...
}

and then any compile-time errors that occur within my_library_namespace
would produce the shortened display without the instantiation stack.

>Cool. Technically, it's not valid either to omit default parameters
>as there might be new default parameters. This may be good in a .cc
>file.


To cater for these tricky cases, the compiler will definitely need a switch
to provide the full diagnostic output.

,Brian Parker
(bpa...@uq.net.au)

Brian Parker

unread,
Jan 26, 1999, 3:00:00 AM1/26/99
to
Andrei Alexandrescu wrote in message <36acb...@10.1.1.65>...
>...

>No matter what, the nicest thing would be to have means for "smart" error
>messages that apply not only to the standard library, but also to client
>code and other libraries. The techniques should be general enough.

All my suggestions are intended to be useful in third party libraries as
well.

>
>Besides, I think the point of instantiation stack should also be displayed.


Agreed, for errors in *user code* as opposed to errors deep within library
code.

>...


>"Compile-time assumption failed: 'sizeof(int) == sizeof(long)' is false"
>
>It would be great if you can achieve this with pragmas. Wow! Can't believe
>that I could actually have such a great compiler. Any ideas?


Interestingly, it was when implementing such a compile-time assertion myself
that I started to think about this issue. I agree that without compiler help
such compile-time assertions are kludges and lead to obscure messages. I
think that a standardised version of #error "msg" that wasn't a part of the
preprocessor but rather understood C++ scoping (called, say, error "msg")
would be useful for this, or maybe simply defining a standard library
version of the compile-time assertion function would be enough (being a part
of the standard library, an implementation could give it special compiler
support).

I concluded, though, that the issue of providing a good compile-time
assertion check was a separate (albeit useful) one to the issue of providing
good compile-time diagnostics from library code (I think that requiring the
implementor to pepper his/her library code with redundant compile-time
assertions is not a viable option).

,Brian Parker
(bpa...@uq.net.au)

Brian Parker

unread,
Jan 30, 1999, 3:00:00 AM1/30/99
to
Thanks for everone's comments in this thread.
This is a summary of the final scheme that I have implemented in ecgs. I
will use it myself for a while longer until it is stable, then I will
release the source and some binaries for wider testing.

The main improvement is a new #pragma libinterface.
The syntax of this is as follows-
#pragma libinterface namespace_name "Library description".

When this is encountered, the compiler knows that functions and classes
within the specified namespace are part of a library, and so when displaying
the instantiation chain on a template error it will only display the chain
down to the library interface and not show the (irrelevant) implementation
details of the library.

A simple example is-

#pragma libinterface GG "My sample library"

class Tester{
};

namespace P2 {
template<typename T>
bool insert(T rhs) {return rhs < T();}
}

namespace P {

template<typename T>
bool insert2(T rhs) {return P2::insert(rhs);}
}

namespace GG {

template<typename T>
void func2(const T& t){

P::insert2(t);
};

}

namespace XX {


template<typename T>
void func1(const T& t){

GG::func2(t);
}
}

int main()
{
Tester t;
XX::func1(t);
}

Without the #pragma, the message from ecgs is-

bptest.cpp: In function `bool P2::insert<Tester>(class Tester)':
bptest.cpp:61: no match for `Tester & < Tester'
bptest.cpp:67: instantiated from `P::insert2<Tester>(Tester)'
bptest.cpp:75: instantiated from `GG::func2<Tester>(const Tester &)'
bptest.cpp:84: instantiated from `XX::func1<Tester>(const Tester &)'
bptest.cpp:101: instantiated from here

(As you may notice, I have made some changes to the default ecgs output as
well)

With the #pragma, we get-

Error using 'My sample library'. Error was:
" no match for `Tester & < Tester' "
bptest.cpp: In instantiation of `GG::func2<Tester>(const Tester &)':
bptest.cpp:84: instantiated from `XX::func1<Tester>(const Tester &)'
bptest.cpp:101: instantiated from here

i.e. only the instantiation chain down to the library interface is shown-
presumably the library documentation will describe the requirements of
GG::func2 and so the problem is immediately apparent.
Of course this trivial example doesn't demonstrate the full utility of this
#pragma- libraries such as STL can generate huge instantiation chains
otherwise.

Note that I will add a compiler switch to disable the effect of the #pragma
in case the full message is required.

Things I haven't implemented (yet) are-

(1) I hope to add a compile-time assertion "assertct(cond,msg)" that has
compiler support to generate a compile-time error if cond is false, and
output msg as the error.

(2) Using typedef names and symbolic constant names in template error
messsages. Ecgs already displays typedefs at the top of the instantiation
chain but doesn't use them throughout, so this will probably not be too hard
to fix.

(3) Elide display of default template parameters. I think this will require
more extensive changes to ecgs.

As always, further comments are welcome.

0 new messages