This is pretty minor, but thought I'd point it out. struct complex { #if 0 constexpr complex(double r, double i) : re(r), im(i) { } #else complex(double r, double i) : re(r), im(i) { } #endif constexpr double real() { return re; } double imag() const { return im; } private: double re; double im; }; constexpr complex co1(0, 1); // literal object //constant expression data initialized by a user-defined literal constexpr double dd2 = co1.real(); // OK with: %$bin/H-x86_64-gcc-constexpr.20101004/bin/g++ --version g++ (GCC) 4.6.0 20101004 (experimental) like so: %$bin/H-x86_64-gcc-constexpr.20101004/bin/g++ -std=c++0x -c constexpr-basic.cc gives: constexpr-basic.cc:9:20: error: enclosing class of ‘constexpr double complex::real() const’ is not a literal type YES! Except the member function signature for real() has a superfulous "const" constexpr-basic.cc:17:27: error: the type ‘const complex’ of constexpr variable ‘co1’ is not literal YES! Except this is more like "invalid definition of constexpr variable 'co1' of non-literal type 'complex' constexpr-basic.cc:20:33: error: ‘double complex::real() const’ is not a constexpr function NO! Perhaps the last one should read: constexpr-basic.cc:20:33: error: member function ‘constexpr double complex::real()’ cannot be used in a constant expression with a non-literal object Or something.
(In reply to comment #0) > constexpr-basic.cc:20:33: error: ‘double complex::real() const’ is not a > constexpr function > > NO! Yes. It is not valid for real() to be constexpr in a non-literal class, so it is not constexpr.
> It is not valid for real() to be constexpr in a non-literal class This is a helpful diagnostic. The existing one is not. -benjamin
(In reply to comment #2) > > It is not valid for real() to be constexpr in a non-literal class > > This is a helpful diagnostic. The existing one is not. constexpr-basic.cc:9:20: error: enclosing class of ‘constexpr double complex::real() const’ is not a literal type isn't clear enough? How about "non-static member function %D declared 'constexpr' in non-literal type" ?
This is going to be re-purposed into a more general bugreport about constexpr and diagnostics. The goal is to try and get compiler messages about why code constructs are or are not valid constant expressions that contain: 1) locality as to where the problem is 2) clarity as to what the problem is 3) notes as to potential fixes. Now, on to the attachments.
Created attachment 22256 [details] constexpr diagnostics test case #01 This is a test case that shows locality information for failed constant expressions in a simple class hierarchy. The test case is comprised of a base class with member data, and no constexpr constructor. The error is: %$bin/H-x86_64-gcc-trunk.20101101/bin/g++ -g -std=gnu++0x constexpr-diagnostics-base1.cc constexpr-diagnostics-base1.cc:18:19: error: the type ‘const derived’ of constexpr variable ‘obj’ is not literal The error desired is: %$bin/H-x86_64-gcc-trunk.20101101/bin/g++ -g -std=gnu++0x constexpr-diagnostics-base1.cc constexpr-diagnostics-base1.cc:18:19: error: the type ‘const derived’ of constexpr variable ‘obj’ is not literal constexpr-diagnostics-base1.cc:8: error: base class constructor is not "constexpr"
Created attachment 22257 [details] constexpr diagnostics test case #02 This diagnostic is for defaulted constructors. At this point, g++ is going a pretty good job on this diagnostic. This testcase just marks the effort needed to get to this point so that in the future there are no regressions. struct base { int _M_i; constexpr base() = default; }; constexpr base obj; gives: %$bin/H-x86_64-gcc-trunk.20101101/bin/g++ -g -std=gnu++0x constexpr-diagnostics-defaulted.cc constexpr-diagnostics-defaulted.cc:2:8: error: ‘constexpr base::base()’ cannot be declared as constexpr constexpr-diagnostics-defaulted.cc:9:16: error: uninitialized const ‘obj’ [-fpermissive] constexpr-diagnostics-defaulted.cc:2:8: note: ‘const struct base’ has no user-provided default constructor constexpr-diagnostics-defaulted.cc:6:13: note: constructor is not user-provided because it is explicitly defaulted in the class body
Created attachment 22266 [details] constexpr diagnostics test case #03 more locality, from this under-development chrono snippet. %$bin/H-x86_64-gcc-trunk/bin/g++ -c -std=gnu++0x constexpr-diagnostics-location1.cc constexpr-diagnostics-location1.cc: In function ‘void test1()’: constexpr-diagnostics-location1.cc:720:32: error: ‘constexpr std::chrono::duration<_Rep, _Period>::duration(const std::chrono::duration<_Rep2, _Period2>&) [with _Rep2 = int, _Period2 = std::ratio<3600l>, <template-parameter-2-3> = void, _Rep = long int, _Period = std::ratio<1l>]’ is not a constexpr function But what we really want is added note constexpr-diagnostics-location1.cc:155: note: calls non-constexpr function 'duration_cast'
Created attachment 22268 [details] constexpr diagnostics test case #04 This is just a test case for previously-reported-and fixed bug. Let's keep it around to avoid regressions. %$bin/H-x86_64-gcc-trunk/bin/g++ -c -std=gnu++0x constexpr-diagnostics-initalizer1.cc constexpr-diagnostics-initalizer1.cc: In function ‘int main()’: constexpr-diagnostics-initalizer1.cc:21:21: in constexpr expansion of ‘A((* & a1))’ constexpr-diagnostics-initalizer1.cc:21:21: error: the value of ‘a1’ is not usable in a constant expression constexpr-diagnostics-initalizer1.cc:20:13: note: ‘a1’ was not declared ‘constexpr’ What we really need is the last line, the note: 'a1' was not declared constexpr
Oh, i thought of another thing, if non-literal type with a constexpr constructor is used to define a namespace-scope static variable, and the "constexpr" creation cannot be honored, then we should get a helpful note that warns the user that it failed and to anticipate possible dynamic initialization. I don't believe a diagnostic is required in this case but an optional warning might be useful.
Follow up to #9, as per discussions in Batavia and http://gcc.gnu.org/ml/gcc-patches/2010-11/msg02406.html There was some thought of providing an attribute syntax for this, say something like __attribute__((init_constant)) that would warn when the variable wasn't constant initialized. Spelling to be determined....
Know this is not high-priority bug for 4.6.0 but it should be as constexpr is a new feature and the initial QoI for diagnostics is important for user's first impressions. Diagnostics are lagging, as this is a new form of C++ diagnostic: there are some interesting opportunities here. We can do better!! I've given some examples, but I'm not quite sure what is required and what Jason and Gaby are thinking in terms of how this stuff should be architected. Thoughts or sketches guys? If a plan can be outlined here in bugzilla, then perhaps it could be split into smaller parts and independently executed?
Author: jason Date: Wed Jun 29 14:34:58 2011 New Revision: 175646 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=175646 Log: PR c++/45923 * class.c (explain_non_literal_class): New. (finalize_literal_type_property): Call it. * cp-tree.h: Declare it. * semantics.c (ensure_literal_type_for_constexpr_object): Call it. (is_valid_constexpr_fn): Likewise. (massage_constexpr_body): Split out from... (register_constexpr_fundef): ...here. (is_instantiation_of_constexpr): New. (expand_or_defer_fn_1): Leave DECL_SAVED_TREE alone in that case. (explain_invalid_constexpr_fn): New. (cxx_eval_call_expression): Call it. (potential_constant_expression_1): Likewise. Avoid redundant errors. * method.c (process_subob_fn): Diagnose non-constexpr. (walk_field_subobs): Likewise. (synthesized_method_walk): Don't shortcut if we want diagnostics. (explain_implicit_non_constexpr): New. (defaulted_late_check): Use it. * call.c (build_cxx_call): Remember location. Added: trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/cp/class.c trunk/gcc/cp/cp-tree.h trunk/gcc/cp/method.c trunk/gcc/cp/semantics.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
Also it seems the destructor must be defaulted. I thought (incorrectly) that only constructors mattered, so tried: protected: ~Base() {} which yields for members: error: enclosing class of '...' is not a literal type and for nonmembers: error: invalid return type 'Derived' of constexpr function '...' but this works: protected: ~Base() = default; specifically, a 'literal type' requires literal members and bases and: * a trivial default constructor or at least one constexpr constructor besides the copy/move constructors (3.9 #10). * a trivial destructor: non-virtual, non-deleted, non-user-provided (12.4 #3)
I believe this is now fixed.