Incorrect generated code for conditional
Win7 - 64bit gcc (GCC) 4.8.2 g++ -w -DYYDEBUG=1 -DDEBUG_IO -c -g -MMD -MP -MF "build/Debug/Cygwin-Windows/SlipRegister.o.d" -o build/Debug/Cygwin-Windows/SlipRegister.o SlipRegister.cpp There is no generated code for "retval = true;" in the conditional block. I am including the code fragment and disassembled code. If the issue seems to be a bug then I will include whatever additional data is required to help gcc identify the error. If it is not a bug then I truly apologize for wasting your time. What happens is that the conditional is executed but there is no required code. art - source code -- bool SlipRegister::post(const string& name, SlipHeader& head) { bool retval = false; if (!head.isHeader()) { postError(SlipErr::E4002, "SlipRegister::post", "", "", head); } else { // attempt to insert a new entry SlipAsciiEntry entry(name, &head, SlipHashEntry::DEFINED); SlipHash::ReturnTuple tuple = hashTable->insert(entry); if (tuple.condition == SlipHash::ReturnTuple::INSERTED) { retval == true; // skipped over } else if (tuple.condition == SlipHash::ReturnTuple::FOUND) { if (fsm(*tuple.entry, SlipHashEntry::DEFINED)) { ((SlipHeader*)((tuple.entry)->getBinaryKey()))->moveListRight(head); head.deleteList(); retval = true; } else if ((tuple.entry)->getType() == SlipHashEntry::USERDATA) { postError(SlipErr::E4001, "SlipRegister::post", "", "", head); } else { postError(SlipErr::E4015, "SlipRegister::post", "", "", head); }; } } DEBUG(debugFlag, cout << sFlag[retval] << "post(" << name << ", " << head.toString() << ") " << endl;) return retval; }; // bool SlipRegister::post(const string& name, SlipHeader& head, bool defineFlag) --- disassembled code fragment ! SlipHash::ReturnTuple tuple = hashTable->insert(entry); slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+337: mov 0xb0(%rbp),%rax slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+344: mov (%rax),%rdx slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+347: lea -0x20(%rbp),%rax slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+351: lea -0x50(%rbp),%rcx slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+355: mov %rcx,%r8 slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+358: mov %rax,%rcx slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+361: callq 0x10042d316 slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+987: lea -0x20(%rbp),%rax slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+991: mov %rax,%rcx slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+994: callq 0x1004e6c60 slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+1509: lea -0x20(%rbp),%rax slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+1513: mov %rax,%rcx slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+1516: callq 0x1004e6c60 slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+1521: jmp 0x10045c4e4 slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+1523: mov %rax,%rbx ! if (tuple.condition == SlipHash::ReturnTuple::INSERTED) { slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+366: mov -0x14(%rbp),%eax slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+369: cmp $0x4,%eax slip::SlipRegister::post(std::string const&, slip::SlipHeader&)+372: je 0x10045c2c9 ! retval == true; ! } else if (tuple.condition == SlipHash::ReturnTuple::FOUND) {
Possible issue with integer promotion for << and >> in gcc.4.5.3
Cygwin gcc 4.5.3 I have run some tests to determine the gcc 4.5.3 integer promotion policies. The tests show that for 'char' input, "char << long" and "char >> long" promote to INT while other operations using a long promote to" long", and that "char << ulong" and "char >> ulong" promote to INT while other operations using ulong promote to "ulong". In similar fashion, "long << long" and "long >> long" promote to INT while other promotions are to long, and that "long << ulong" and "long >> ulong" promote to long while other operations promote to ulong. The code used and the output are included below. The code is not production code. I think the code is correct and that my interpretation is also correct. I realize that gcc 4.5.3 is no longer supported so if my guess is correct do I have to switch to mingw (for precompiled later compilers)? output func0(char 1) !x 0 0x BOOL ~x-2 0xfffe INT +x 1 0x0001 INT -x-1 0x INT ++x3 0x0002 CHAR --x -1 0x CHAR x++2 0x0001 CHAR x--0 0x0001 CHAR func1(char -1, bool true) x + y0 0x INT x - y -2 0xfffe INT x * y -1 0x INT x / y -1 0x INT x % y1 0x0001 INT x << y -2 0xfffe INT x >> y -1 0x INT x & y1 0x0001 INT x | y -1 0x INT x ^ x -2 0xfffe INT func1(char -1, char 1) x + y0 0x INT x - y -2 0xfffe INT x * y -1 0x INT x / y -1 0x INT x % y1 0x0001 INT x << y -2 0xfffe INT x >> y -1 0x INT x & y1 0x0001 INT x | y -1 0x INT x ^ x -2 0xfffe INT func1(char -1, uchar 1) x + y0 0x INT x - y -2 0xfffe INT x * y -1 0x INT x / y -1 0x INT x % y1 0x0001 INT x << y -2 0xfffe INT x >> y -1 0x INT x & y1 0x0001 INT x | y -1 0x INT x ^ x -2 0xfffe INT func1(char -1, long 1) x + y0 0x LONG x - y -2 0xfffe LONG x * y -1 0x LONG x / y -1 0x LONG x % y1 0x0001 LONG x << y -2 0xfffe INT x >> y -1 0x INT x & y1 0x0001 LONG x | y -1 0x LONG x ^ x -2 0xfffe LONG func1(char -1, ulong 1) x + y0 0x ULONG x - y 4294967294 0xfffe ULONG x * y 4294967295 0x ULONG x / y 4294967295 0x ULONG x % y1 0x0001 ULONG x << y -2 0xfffe INT x >> y -1 0x INT x & y1 0x0001 ULONG x | y 4294967295 0x ULONG x ^ x 4294967294 0xfffe ULONG func0(long 1) !x 0 0x BOOL ~x-2 0xfffe LONG +x 1 0x0001 LONG -x-1 0x LONG ++x3 0x0003 LONG --x -1 0x LONG x++2 0x0001 LONG x--0 0x0001 LONG func1(long -1, bool true) x + y0 0x LONG x - y -2 0xfffe LONG x * y -1 0x LONG x / y -1 0x LONG x % y1 0x0001 LONG x << y -2 0xfffe LONG x >> y -1 0x LONG x & y1 0x0001 LONG x | y -1 0x LONG x ^ x -2 0xfffe LONG func1(long -1, char 1) x + y0 0x LONG x - y -2 0xfffe LONG x * y -1 0x LONG x / y -1 0x LONG x % y1 0x0001 LONG x << y -2 0xfffe LONG x >> y -1 0x LONG x & y1 0x0001 LONG x | y -1 0x LONG x ^ x -2 0xfffe LONG func1(long -1, uchar 1) x + y0 0x LONG x - y -2 0xfffe LONG x * y -1 0x LONG x / y -1 0x LONG x % y1 0x0001 LONG x << y -2 0xfffe LONG x >> y -1 0x LONG x & y1 0x0001 LONG x | y -1 0x LONG x ^ x -2 0xfffe LONG func1(long -1, long 1) x + y0 0x LONG x - y -2 0xfffe LONG x * y -1 0x LONG x / y -1 0x LONG x % y1 0x0001 LONG x << y -2 0xfffe LONG x >> y -1 0x LONG x & y1 0x0001 LONG x | y -1 0x LONG x ^ x -2 0xfffe LONG func1(long -1, ulong 1) x + y0 0x ULONG x - y 4294967294 0xf
Diagnostic Messaging Suggestion
Please take the comments as constructive and not adversarial. I use GCC and have hopes of sending it a Valentine's Day gift. 1: Any thought to including column numbers with line numbers on ERROR messages? Looking at a diagnostic message for a complex statement without a column number has lead to making an incorrect assumption as to what in the line is faulty. A column number would help to identify the fault. 2: Stream errors are tortuous to decode to find the cause of error..Any thought to simplification? In particular: 'stream << something_wrong;' can produce a multiline message with copious use of the templates used - but no simple statement as what the error is. 3: A simple error: 'ifstream istream;' Leads to an diagnostic message which seems remote from the problem. Most diagnostic messages contain some indication of what the failure is and what to do to repair them. Some messages are outstanding. But then again, some could probably use a little tweaking. Any thoughts? art
Re: Diagnostic Messaging Suggestion
I didn't mean to volunteer. I'm retired and therefor am both unhireable and hove no free time. But if you really (really) want ... I'd be glad to contribute in any way that I can. Provide what you need that I can do, and a means to give you feedback and I'm yours. (I've already provided an indication of a willingness to do something to Robert Dewar). art
Possible messaging changes
In light of the foolhardy commitment I made, here are some reprehensible diagnostic messages and the superb recanting of the obvious. As always, the messaging and comments are gratuitously provided and I hope accepted in the same manner. Two notes (made before): 1: Some messages are needlessly garrulous. You have noted this previously. 2: The length of some diagnostic messages extend beyond reason. You have noted this previously. 3: In a general environment with many classes, structures, typedef's, etc. the clear association of a diagnostic message with the offending object, type, etc. ads clarity. The messages included below have no clear association (although we might argue that garrulity adds clarity). 4: Code is not self-documenting, sic COBOL, and diagnostic messages aren't either. A document with messaging guidelines, message descriptions, or anything else might be useful. Sigh, I can probably help with this. As a suggestion, since all headers (and included symbols) are known prior to compilation it might be possible to put all the 'names' into a symbol table for use during error generation. This allows gcc to (perhaps) publish candidate solutions when type errors are detected (see m3). As (yet another) suggestion, since user headers can be processed independently of code (without considering edge conditions) ya' might as well augment the first suggestion with user symbols. And yet again, while processing a given code file, symbols contained in the code file can be used to (yet again) augment the symbol table for use in diagnostic generation. And NOW for the failures! /* * m1.cpp */ # include # include using namespace std; ifstream x; ifstream& y = x; int main(int argc, char** argv) { y = x; return 0; } g++.3.4.4 output m1.cpp: In member function `std::basic_ios >& std::basic_ios >::operator=(const std::basic_ios >&)': /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ios_base.h:784: error: `std::ios_base& std::ios_base::operator=(const std::ios_base&)' is private m1.cpp:10: error: within this context m1.cpp: In member function `std::basic_filebuf >& std::basic_filebuf >::operator=(const std::basic_fil ebuf >&)': /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/streambuf:776: error: `std::basic_streambuf<_CharT, _Traits>& std::basic_streambuf<_CharT, _Traits>::operator=(con st std::basic_streambuf<_CharT, _Traits>&) [with _CharT = char, _Traits = std::char_traits]' is private m1.cpp:10: error: within this context Almost indecipherable. The error is that operator=() is private. "error: assignment illegal, operator '=' private in ifstream" /* * m2.cpp */ using namespace std; ifstream x; ifstream y(); int main(int argc, char** argv) { return 0; } g++.3.4.4 output m2.cpp:4: error: `ifstream' does not name a type m2.cpp:5: error: `ifstream' does not name a type Succint and clear message, however it might be clearer to say that "'ifstream' not found" since the message says that 'ifstream' may be something other than a type. "error: ifstream not found" "note: candidates are in #include " /* * m3.cpp */ # include # include using namespace std; ifstream x; ifstream y(); int main(int argc, char** argv) { return 0; } g++3.4.4 messaging m3.cpp:6: error: aggregate `std::ifstream x' has incomplete type and cannot be defined m3.cpp:6: error: storage size of `x' isn't known Messaging not clear. The naive issue is the 'ifstream' not found. 'std::ifstream' not found. 'std::ifstream x' is confusing. If 'std::ifstream' not found, why is 'std::ifstream y();' legal? "error: ifstream incomplete in 'istream'.
Redirecting I/O
This isn't a compiler question and I apologize for that. I'm having a devil of a time getting an answer to my issues on the C/C++ forums I'm using and, sigh, perhaps someone can direct me to a forum where the questions can be better addressed. I'm trying to redirect I/O in my C++ application and am having some difficulty. I am trying to use cout or a file for output based on some condition. cout is an ostream object and file is an ofstream object. The types are incompatible, as in: bool condition; ofstream x; ofstream out = (condition)?cout: x; // won't work because of cout int main(..){ out = cout;// won't work } In addition I would like to redirect an ofstream object to be the same as out, as in; void fn() { object = out; } // won't work because '=' is private. Anyone know how to solve these two issues?
operator=() issue
operator=() is private in ios_base. Using private inheritance of ios_base the program below fails in the constructor when '=' is used (but not during memory initialization). I don't understand why assignment is prohibited. art Program 1 fails # include using namespace std; class thing : private ios_base { ostream& xo; public: thing(ostream& y) : xo(y) { xo = y; } }; gcc.3.4.4 messaging x.cpp: In member function `std::basic_ios >& std::basic_ios >::operator=(const std::basic_ios >&)': /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ios_base.h:784: error: `std::ios_base& std::ios_base::operator=(const std::ios_base&)' is private x.cpp:9: error: within this context Program 2 succeeds # include using namespace std; class thing : private ios_base { ostream* yo; public: thing(ostream& y) { yo = &y; } thing(ostream y) { yo = &y; } }; Program 4 fails # include using namespace std; class thing : private ios_base { ios_base& xo; public: thing(ios_base& y) { xo = y; } }; gcc.3.4.4 messaging x.cpp: In constructor `thing::thing(std::ios_base&)': x.cpp:9: error: uninitialized reference member `thing::xo' /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ios_base.h:784: error: `std::ios_base& std::ios_base::operator=(const std::ios_base&)' is private x.cpp:9: error: within this context
Re: operator=() issue
You understood me correctly. My (mis?)understanding comes from: The Complete Reference,Fourth Edition Herbert Schildt Copyright 2003 ISBN 0-07-222680-3 Page 420 (And I Quote - don't you just love the phrase) "Remember: When a base class' access specifier is private, public and protected members of the base become private members of the derived class. This means that they are still accessible by members of the derived class but cannot be accessed by parts of your program that are not members of either the base or derived class." If you can, could you please provide a citation which contradicts Schildt? The examples have a derived class with a private access specifier to a base class which should allow access to base class private members, and I assume, functions - there is no privacy when you are so derived. Given the above quote the behavior seen by gcc is unexpected. Given your statement it appears that an access specifier of 'private' has no effect. art --- On Fri, 4/10/09, Ian Lance Taylor wrote: > From: Ian Lance Taylor > Subject: Re: operator=() issue > To: "Arthur Schwarz" > Cc: gcc@gcc.gnu.org > Date: Friday, April 10, 2009, 4:48 PM > Arthur Schwarz > writes: > > > operator=() is private in ios_base. Using private > inheritance of > > ios_base the program below fails in the constructor > when '=' is used > > (but not during memory initialization). I don't > understand why > > assignment is prohibited. > > Perhaps I misunderstand your question, but private > inheritance does not > grant access to private methods in the parent class. > It merely > prohibits access to the parent class by users of the > class. > > Ian >
Re: operator=() issue
To all, I stand abashed - don't try this without a trained instructor. I misread the Schildt quote and (I think) wasted your time(s). Thank you art --- On Fri, 4/10/09, David Fang wrote: > From: David Fang > Subject: Re: operator=() issue > To: "Arthur Schwarz" > Cc: gcc@gcc.gnu.org > Date: Friday, April 10, 2009, 5:45 PM > One more thing to add ... > > >> Program 1 fails > >> # include > >> > >> using namespace std; > >> > >> class thing : private ios_base { > >> ostream& xo; > >> public: > >> thing(ostream& y) : xo(y) { xo = > y; } > >> }; > >> > >> gcc.3.4.4 messaging > >> x.cpp: In member function `std::basic_ios std::char_traits >& > std::basic_ios > >::operator=(const std::basic_ios std::char_traits >&)': > >> > /usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/ios_base.h:784: > error: `std::ios_base& std::ios_base::operator=(const > std::ios_base&)' is private > >> x.cpp:9: error: within this context > > > > std::ios_base was never meant to be > copy-able/assign-able, this has nothing to do with > public/private *inheritance*, since it is the members of the > base that are private, and thus inaccessible to any derived > classes. > > > > In your thing::thing ctor: > > > > "xo(y)" initializes the member *reference* > (essentially taking the address of y), whereas "xo = y;" is > assigning the *object* referenced by 'ox', which is not the > same. This is why you hit the inaccessible assignment > error. > > The real problem is that you are assigning an ostream to an > ostream, which is not allowed *in any context* because > ostream ultimately derives from ios_base, which privatizes > assignment. You are seeing this message about ios_base > (misleading you to think it has to do with your thing class > inheriting from ios_base) because the default assignment of > class ostream (not explicitly defined) is invoking the > default assignments of its base classes, including > ios_base. This is more an issue of mis-using the > standard ostream class. > > Fang > > David Fang > http://www.csl.cornell.edu/~fang/ > http://www.achronix.com/ > >
messaging
In the following code fragment: # include # include # include using namespace std; void CommandLine(int argc, char** argv); int main(int argc, char** argv) { CommandLine(argc, argv[]); ifstream x.open(argv[1], ios:in); ofstream y.open(argv[1], ios::in); return 0; }; g++-4 messaging is: >> g++-4 x.cpp x.cpp: In function 'int main(int, char**)': x.cpp:8: error: expected primary-expression before ']' token x.cpp:10: error: expected primary-expression before ':' token A recommendation and reason for change is: 1: x.cpp:8 error: illegal to pass an array without subscript value as an argument The given message is accurate but non-expressive of the reason for failure. 3: cpp:10 error: illegal scope resolution operator ':' From memory, there are three uses of ':' in C++ ':' label terminator, : ':' case in a switch statement, case : ':' scope resolution operator, "::" The given diagnostic message is deceptive. art
messages
Some messaging observations for the input code (below). # include # include # include using namespace std; void CommandLine(int argc, char** argv); int main(int argc, char** argv) { string a = "output.txt"; string* b = &a; ofstream y; y.open("output.txt", ios::in); y.open( a, ios::in); y.open( a.c_str(), ios::in); y.open((*b).c_str(), ios::in); y.open( a.c_str, ios::in); return 0; }; g++-4 x.cpp with suggested error messages and reasoning x.cpp: In function 'int main(int, char**)': x.cpp:12: error: no matching function for call to 'std::basic_ofstream >::open(std::string&, const std::_Ios_Openmode&)' /usr/lib/gcc/i686-pc-cygwin/4.3.2/include/c++/fstream:626: note: candidates are: void std::basic_ofstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode ) [with _CharT = char, _Traits = std::char_traits] x.cpp:15: error: no matching function for call to 'std::basic_ofstream >::open(, const std::_I os_Openmode&)' /usr/lib/gcc/i686-pc-cygwin/4.3.2/include/c++/fstream:626: note: candidates are: void std::basic_ofstream<_CharT, _Traits>::open(const char*, std::_Ios_Openmode ) [with _CharT = char, _Traits = std::char_traits] >> 1: error: open(arg1, ...) must be a C-string. The existing message is indecisive in it's resolution. It might be an acceptable idea to analyze expected input arguments and compare them with actual arguments and then state a reason for failure based on the actual argument(s) that failed. This is a labor since for (example) if arg1 is valid for some overloaded functions but arg2 is invalid for any functions, and then arg2 is valid for some functions but arg1 is invalid for any function then there is a processing overhead at diagnostic generation time. My argument is that one function of a compiler is show the cause of failure in unambiguous and clear terms. 2: error: open(arg1, ...) must be a C-string, and error: a.c_str not a member of 'a' The first failure is the inability to find a valid member of 'a'. This leads to the second failure of being unable to find an overloaded open. Nowhere is this clear from the messaging. We have discussed the undue length of messaging before. art
Re: messages
Thanks Dave;' Acerbic comments below. --- On Mon, 4/13/09, Dave Korn wrote: > > using namespace std; > > void CommandLine(int argc, char** argv); > > int main(int argc, char** argv) { > > string a = "output.txt"; > > string* b = &a; > > ofstream y; > > > y.open("output.txt", ios::in); > > y.open( a, > ios::in); > > y.open( a.c_str(), > ios::in); > > > y.open((*b).c_str(), ios::in); > > y.open( a.c_str, > ios::in); > > return 0; > > }; > > > 1: error: open(arg1, ...) must be a C-string. > > The existing message is indecisive in > it's resolution. It might be > > an acceptable idea to analyze expected > input arguments and compare > > them with actual arguments and then state > a reason for failure based > > on the actual argument(s) that failed. > > Isn't that exactly what the compiler IS doing, as > indicated by "candidates > are ... "? I don't think so. The compiler is directing the user to a given solution and specifying what the problem is, the compiler is essentially saying that it found something it couldn't resolve and for the user to find out where and what is wrong. A clear message that arg is wrong I think is a better approach. The compiler provides candidate solutions, without guidance, and the user must search the candidates (and arguments) to determine where the fault lies. > > > overhead at diagnostic generation time. > My argument is that one > > function of a compiler is show the cause > of failure in unambiguous > > and clear terms. > > It's not always possible for the compiler to do > that. How can it know if > the problem is that you gave the wrong argument type in the > function call, > rather than that you got the type wrong in the definition > of the overloaded > function that was supposed to match? Even accepting your statements as accurate some of the time I think it a good diagnostic tool for the user for the compiler to do what it can when it can. If the judicious answer is that the cases where such a tool could be provided is an edge condition where there is small chance of occurrence, why then (to be forceful - ahem - needlessly vehement) let the user suffer. > > > x.cpp:15: error: no matching function for call to > > 'std::basic_ofstream std::char_traits >::open( overloaded function type>, const > std::_I > > os_Openmode&)' > /usr/lib/gcc/i686-pc-cygwin/4.3.2/include/c++/fstream:626: > > note: candidates > are: void std::basic_ofstream<_CharT, > _Traits>::open(const char*, > std::_Ios_Openmode > > ) [with _CharT = char, _Traits = > std::char_traits] > > > 2: error: open(arg1, ...) must be a C-string, and > > error: a.c_str not a member of 'a' > > The first failure is the inability to > find a valid member of 'a'. > > Err, are you sure? I think 'c_str' > absolutely is a member of a, see two > lines earlier. The actual problem is that without the > brackets, that's a > function pointer that you're trying to pass when y.open() > expects a string. And I agree. My analysis is faulty in that the member function is seen, but the diagnostic message doesn't say what's wrong. The determination of what the error is is left to the casual observer. > > BTW, have you ever tried STLfilt? It's highly > relevant to your interests: No I haven't but now that I know something exists I probably will. Before I toodle off, let me put some kinder words around what I'm doing. I'm not pointing fingers or poking fun. As a result of my own lacks it was suggested that I volunteer to provide alternatives to diagnostic messaging for the gcc to consider. They are apparently directly addressing the issues involved with constructing user oriented diagnostic messages and asked me to volunteer to send what I thought could be changed for their consideration. The examples given are designed only to illustrate messaging and alternative wording for consideration. Each day I address my 'skills' in software and find they are more modest than first thought. There is no thought to impose myself on the organization or criticize anything in this product. Anything at all. Nada. Nothing. In brief, the examples are not meant to display what I don't know or seek resolution of my lack of skill. > > http://www.bdsoft.com/tools/stlfilt.html > > cheers, > DaveK > Thanks again. art > >
Re: messages
> > Thanks Dave;' > > > > Acerbic comments below. > > >> Isn't that exactly what the > compiler IS doing, as > >> indicated by "candidates are ... "? > > > > I don't think so. [ ... ] A clear > message that arg is wrong I think > > is a better approach. > > But maybe arg is right and it's something > else that is wrong? > > >> It's not always possible for the > compiler to do > >> that. > > > Nonono; I didn't mean to impugn anything you're > doing, just trying to point > out that it's not easy. Impugn away. I am terribly thin-skinned and the barbs wake me up. > > Should the compiler always assume the function prototypes > are correct and the > choice of argument in the function call is wrong? It > occurs to me that that > might be a good rule of thumb for system headers, but > probably not for headers > within the user's application. In this case the compiler detected an error and provided the correct answer, but the answer lacked clarity for (really) a non-compiler writer. Before I say another word (let's see you deal with that one), if we look at the statement you have made then, I think, we are left nowhere. In particular your caveat on when my suggested reporting algorithm is inapplicable. To tear into the statement and bring you to a proper state of receptiveness, in absurdum you are saying that even though the compiler has detected an error and reported (what it thinks) is an error, the compiler is unable to determine that the error occurred in arg - the nub of the suggested diagnostic message. I would say that given the existing compiler message, if the compiler can't draw this conclusion then the message is wrong. I would then say if the compiler is clever enough to provide a function template as a candidate for correcting the fault, then the compiler has all of the information needed to do a comparison, argument by argument, to determine which argument(s) are at fault, and can do this recursively (or iteratively if you're going to get picky) with all candidate function solutions. I believe your caveat is then moot. The existing diagnostic message should be sufficient to allow the compiler to perform the analysis necessary to provide a more 'user friendly' (according to 'art') fault indication. I would go further by saying that (especially) any time the compiler is able to provide a candidate solution then the compiler should be able to analyze it's own solution against the fault to provide a more meaningful message. I assert that in those cases where compiler fault analysis fails, then under the stated conditions above the compiler has provided a faulty initial analysis of the problem and that is a 'bug'. Conventional wisdom, in my youth when the Sun shone brighter, was that error analysis was O(n**3), so I acknowledge that this is not easy. My argument is that the compiler has already done the analysis and just fails on the messaging. I believe that it is possible to generalize the analysis tool and avoid case-by-case special purpose code for each 'nasty'. If not completely for all cases and forever, at least for enough cases to make the effort worthwhile. My reasoning is that most semnatic errors fall into broad categories, call it a 'failure in semantics', and these broad categories can be leveraged into a generic toolset. The pragmatic difficulty is that that existing diagnostic messages would have to be reworked into a standardized framework, and I view this as a hard problem. (Mind you, this is all without doing a lick of work or seeing a line of code - obviously I'm an expert.) Now, whew, I may be all wrong and if so, please be gentle. art
Re: messages
--- On Mon, 4/13/09, Joe Buck wrote: them all. > > Consider > > #include > struct Foo { int bar;}; > int main() { > std::cerr << Foo(); > } > > Try it, the result is ugly, and I often encounter this one (Personal opinion - not to be construed as wisdom). The issue with the result is: 1: There is no end-of-line between candidates (or anywhere). 2: The candidate template is a large, untamed, and unruly beast. 3: The diagnostic message is not clear. I think it should say that the compiler can't find something because of something. 4: Providing a full template for each candidate is (indeed) something of an overkill. And so in substance I agree, in detail there are some mitigating things that can be done. art
Re: messages
> > So I guess, yes, I'm asking Arthur to suggest rules > of relevance that would > enable the compiler to decide what kind of user error is > implied by a given > syntax error. > > cheers, > DaveK > You're asking for a lot. I've never been accused of being smart (the quip being, 'I've always been admired for it'.) In one of my previous e-mails I mentioned a criteria of selection. Do nothing. The compiler already provides adequate analysis. What is missing is an analysis of the analysis to produce more 'user friendly' diagnostic messages. What I think we get is a compiler writers' version of a suitable diagnostic. The messages seem to indicate what a compiler writer needs to determine what is at fault, and perhaps with sufficient detail to determine that the fault (message) is at fault. What I suggested is that a separate subsystem be created to extract 'meaning' from the compiler writers' message, and present a user version of the message. I do not believe that the compiler writers' messaging should be removed - it is useful for compiler writers - just that it be optioned-out for the user. Taking the approach that the existing messages are satisfactory the dialog on relevance moves a tad to the right. The issue becomes one of comparing the detailed messaging to the textual fault. In the original case, one of pointing out that arg is at error because is doesn't match known overloads (and some other name for templates I suppose). In that way, the user is told that arg is at fault rather than having to discover that fact. The error analysis subsystem, in the case of not finding a suitable overloaded function, is one of identifying user provided arguments again found potential overload. Essentially something like: function() overload() arg<1> arg<1> arg2<> arg<2> o o o o o o o o o arg arg and finding which arguments fail. There may be more than one answer and some heuristic is needed to determine which or how many messages to provide for a given failure. To throw an answer of relevancy on the mud-pile, suppose we choose to message the cases where there is the least number of failures. Using this heuristic for this failure the overloads which contain only 1 argument which fails takes precedence over overloads with 2 argument failures and so on. This is a mud-pile heuristic, sufficient to start a discussion but probably not suitable for ending one. In most cases I would find it a daunting task to provide an algorithm to decide which error, among many, is the 'most important' and should be addressed while the others are left unaddressed. The easy answer is to provide an option which details the 'depth' of fault diagnostics to provide - avoiding the problem of finding the best diagnostic but, again, introducing the notion of fault ranking. I also think that for some cases it might be possible to actually establish the 'best' wrong answer. Again, ideas are cheap, work is hard. In one of my previous e-mails I suggested that it might be possible to characterize semantic errors and to standardize existing diagnostic messaging to fit the characterization. The process for many 'user friendly' messages then becomes one of analysis of the cause of faults against the detailed messaging to extract some user oriented messaging. I said that the pragmatics of the approach may be hard. Now I know that this is all hand-waving and random bits of wisdom. There is a wide area for investigation, discussion, and debate. Now that I've ended up confusing myself art
Re: messaging
The issues grow ever more complex. Suppose that we're dealing with macro's, some similarly named, and there's a typo. Suppose several layers of template expansion are involved and nested deep within one there is some error. Suppose, suppose ... . The motivation is not to expand the problem domain to the point were even stating the problem is a problem, but to creep up carefully and gradually on some consensus option as to what to do and then to go forward. All the points made are valid. At a certain time either the diagnostic message can not perceive nor report on the original cause of error, or the report is convoluted enough to be unreadable by all but the most diligent. Let me address some general principles, which, of course, are both mine and may be wrong. 1: The purpose of compiler diagnostics is to present faults to a user in the most economic way possible. 2: The presentation should be a pointed as possible as to the detected fault. 3: The user should be required to understand as little as possible in order to understand the faulting message. The details of specific messaging are not as important as the guidelines. What I have seen in this thread and in a companion thread, messages, are these viewpoints. 1: The user should have some minimal capability to understand the diagnostic messages as they are now. 2: The user is being overwhelmed with information and has difficulty sifting through it. 3: The messages show the fix but not the problem. Clearly I am biased to 2: and 3:. But let me turn to 1; for a moment. In order to develop software in most languages, C++ being only one, it is not necessary to read nor understand the syntax equations for the language. The notion that developers should be compelled to acquire a knowledge of syntax equations won't work in practice. There is no authority to compell this knowledge nor to deny employment (or hobby work) for someone who doesn't have it. It might be nice but ... . So we are left with compiler users with minimal or none of the assumed pre-requisite knowledge. The notion that these unknowledgeable users should be abandoned in provided diagnostic messages eventually translates into the compiler being abandoned by the users. In the small, probably fine. In the large I would think it unacceptable. And there are competitive compilers. Some with better messaging and better messaging resources at the very point where g++ is weakest. You might argue that they are 'better in what way?', but I think the real argument is in what ways can these other products be a model for g++ to improve itself. Unless the notion is that g++ needs no improvement. A reasoned attitude (I think) is to address each item without prejudice and see if there is some common ground, and then to proceed to see what is possible in general and what edge cases can't be simply solved. I think that there is a way to creep upon a general consensus which may not give everyone everything, but will give most something. And I believe the solution is not a 'camel by committee' but a more useable product. art
Diagnostic Messaging Suggestion
Suggested Messaging: Messaging seems redundant in indicating that function has been redifined twice. One of the messages should be removed. More to the point, I think the messaging may be erroneous - code fragment follows. g++-4 Diagnostic Messaging In file included from partition.cpp:66: irange.h: In function 'std::ostream& operator<<(std::ostream&, ciRange_2::sRange_2&)': irange.h:102: error: redefinition of 'std::ostream& operator<<(std::ostream&, ciRange_2::sRange_2&)' irange.h:102: error: 'std::ostream& operator<<(std::ostream&, ciRange_2::sRange_2&)' previously defined here Code Fragment class ciRange_2 : public iRange_List { // public: struct sRange_2 { double RLo;// Low range value double RHi; }; // High range value friend istream& operator>>(istream& stream, ciRange_2::sRange_2& Range); friend ostream& operator<<(ostream& stream, ciRange_2::sRange_2& Range); }; // class ciRange_2 istream& operator>>(istream& stream, ciRange_2::sRange_2& Range); ostream& operator<<(ostream& stream, ciRange_2::sRange_2& Range) { stream << setw(9) << Range.RLo << " " << setw(9) << Range.RHi; }
Re: Diagnostic Messaging Suggestion
> > Can you show code that reproduces the issue? My best > guess is that a > header file is included twice, and lacks guards, hence the > message is > correct: the function is being defined twice, from the same > source > location. > > -- James > Code (unadulterated and full of original lacerations) - /* * File: irange.h * Author: Arthur Schwarz * * Created on April 13, 2009, 1:23 PM */ #ifndef _IRANGE_H #define _IRANGE_H # include # include # include # include # include # include # include "common.h" class iRange_List : public cDebug{ // input ranges private: // Processing of range buffer: // Ranges[Ndx] : Ndx<0..BufferSize-1> // if (Ndx == BufferSize) TempStream.write(Ranges[Ndx]; Size += BufferSize; Ndx = 0; fstream TempStream; // Temporary Stream static long const BufferSize; // Input buffer size longNdx; // Index in Ranges buffer longSize;// Total number ranges used cRange ErrorRange; protected: cRange* Ranges; // All input ranges longErrorCount; // Number of errors found protected: //double Atod(string& Range, long id); virtual void DData () { string str(80, ' '); ostringstream stream(str); stream << "iRange_List<" << setw(9) << Ndx << ", " << setw(9) << Size << ", " << setw(9) << ErrorCount << ">" << endl; cDebug::DData(str); }; long Next() { if ( ++Ndx < BufferSize) return Ndx; TempStream.write((char*)Ranges, sizeof(Ranges)); Size += BufferSize; return (Ndx = 0); }; void Flush(); public: iRange_List(); iRange_List(const iRange_List& orig); virtual ~iRange_List(); long GetSize() { return Size; } void PrintRange() { for(long i = 0; i < Ndx; i++) Stdout << setw(9) << i << ": " << Ranges[i] << endl; }; // PrintRange() virtual bool Read() = 0; cRange& operator[](long Ndx) { return ((Ndx >=0 ) && (Ndx < Size))? Ranges[Ndx]: ErrorRange; } }; // class iRange_List class ciRange_2 : public iRange_List { // public: struct sRange_2 { double RLo;// Low range value double RHi; }; // High range value ciRange_2() : iRange_List() { } virtual bool Read(); friend istream& operator>>(istream& stream, ciRange_2::sRange_2& Range); friend ostream& operator<<(ostream& stream, ciRange_2::sRange_2& Range); }; // class ciRange_2 class ciRange_3 : public iRange_List { // public: struct sRange_3 { double RLo; // Low range value double RHi; // High range value longDatum; }; // User supplied datum ciRange_3() : iRange_List() { } virtual bool Read(); friend istream& operator>>(istream& stream, sRange_3& Range); friend ostream& operator<<(ostream& stream, ciRange_3::sRange_3& Range); }; // class ciRange_3 #endif /* _IRANGE_H */ // //Debug Streams // istream& operator>>(istream& stream, ciRange_2::sRange_2& Range); istream& operator>>(istream& stream, ciRange_3::sRange_3& Range); ostream& operator<<(ostream& stream, ciRange_2::sRange_2& Range) { stream << setw(9) << Range.RLo << " " << setw(9) << Range.RHi; } ostream& operator<<(ostream& stream, ciRange_3::sRange_3& Range) { stream << setw(9) << Range.RLo << " " << setw(9) << Range.RHi << " " << setw(9) << Range.Datum; }
Re: Diagnostic Messaging Suggestion
I forgot to say 'thanks James', thanks. Well, spurred on by the whimsy that I need a solution to the problem (however dolorous), I experimented. I've commented most everything at least once and the net effect is that only the 'operator<<' gets a nasty message. I've checked the include files that I've written and they all seem clean of heresies. The 'operator>>' files are unaffected, and with them gone, I still get an error on the 'operator<<' function. The only thing that I can think of, and I think it remote, is that the functions refer to a public structure internal to a class. The 'operator>>' functions refer to their respective classes. Again, I've removed all of my friends but one 'operator<<' and this gets the error. Now I think I know C++ (although, to be honest, I have strong, personal, doubts) and I can't think what I missed. However, the initial statement still holds, the second diagnostic messages adds no clarity and seems redundant. Further, if there was a cause of conflict with a redefinition, it would be useful to include the original conflicting declaration. Perhaps something like: <>: error: redefinition of function at <> illegal. note: istream& operator>> (bool& val ); istream& operator>> (short& val ); o o o the note: stuff is from cplusplus.com @ http://cplusplus.com/reference/iostream/istream/operator%3E%3E/ So, a concrete suggestion at to messaging and an individual first, a puzzler. I really need help on the puzzler. thanks art
Re: Diagnostic Messaging Suggestion
Thanks to everyone. The rock has dropped. The answer is quoted below: "My best guess is that a header file is included twice, and lacks guards, hence the message is correct: the function is being defined twice, from the same source location." I had put my friends following my 'include guard'. As we all know, when your guard is down you can get sucker-punched. Although you should never try to teach an old dog new tricks, with luck and a good tail wind this will never happen again. thanks art PS: You are now all my best friend. Sorry.
cout Issue
Program and particulars below. When line 27 is commented out, line 26 is output. When line 27 is not commented, line 26 is not output except that if x.file contains a line feed the null line line 26 & line 27 are output. If x.file does not contain a line feed, only line 27 is output. Does the line feed have an effect on the 'cout <<' of line 26 of the program? Note. The code is awful and this is an example. art g++-4 (GCC) 4.3.2 20080827 (beta) 2 x.cpp 1 # include 2 # include 3 # include 4 # include 5 # include 6 7 using namespace std; 8 9 ifstream x("x.file", ios::in); 10 11 struct y { 12 double a; 13 double b; 14 } yNot; 15 16 int main(int argc, char** argv) { 17 char Line[512]; 18 long LineNo = 0; 19 while ( !x.eof() ) { 20 LineNo++; 21 x.getline(Line, 512); 22 istringstream Phfft(Line); 23yNot.a = -1; 24yNot.b = -2; 25Phfft >> yNot.a >> yNot.b; 26cout << setw(4) << LineNo << ": " << Line; 27cout << " a:" << yNot.a << " b:" << yNot.b; 28 cout << endl; 29 } 30 return 0; 31 } x.file 1 2