Bug 45923 - constexpr diagnostics, more more
constexpr diagnostics, more more
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: c++
unknown
: P3 normal
: 4.7.0
Assigned To: Jason Merrill
: diagnostic
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2010-10-06 23:58 UTC by Benjamin Kosnik
Modified: 2014-11-18 07:49 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-06-27 04:09:51


Attachments
constexpr diagnostics test case #01 (200 bytes, text/plain)
2010-11-03 17:37 UTC, Benjamin Kosnik
Details
constexpr diagnostics test case #02 (82 bytes, text/plain)
2010-11-03 17:42 UTC, Benjamin Kosnik
Details
constexpr diagnostics test case #03 (20.45 KB, text/plain)
2010-11-03 20:48 UTC, Benjamin Kosnik
Details
constexpr diagnostics test case #04 (284 bytes, text/plain)
2010-11-03 20:55 UTC, Benjamin Kosnik
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Benjamin Kosnik 2010-10-06 23:58:09 UTC
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.
Comment 1 Jason Merrill 2010-10-07 15:35:45 UTC
(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.
Comment 2 Benjamin Kosnik 2010-10-08 17:12:35 UTC
> 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
Comment 3 Jason Merrill 2010-10-08 18:37:52 UTC
(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"

?
Comment 4 Benjamin Kosnik 2010-11-03 17:32:23 UTC
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.
Comment 5 Benjamin Kosnik 2010-11-03 17:37:39 UTC
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"
Comment 6 Benjamin Kosnik 2010-11-03 17:42:08 UTC
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
Comment 7 Benjamin Kosnik 2010-11-03 20:48:38 UTC
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'
Comment 8 Benjamin Kosnik 2010-11-03 20:55:42 UTC
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
Comment 9 Benjamin Kosnik 2010-11-11 04:54:49 UTC
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.
Comment 10 Benjamin Kosnik 2010-11-24 20:44:49 UTC
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....
Comment 11 Benjamin Kosnik 2011-01-20 19:27:27 UTC
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?
Comment 12 Jason Merrill 2011-06-29 14:35:03 UTC
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
Comment 13 Ben Longbons 2011-07-05 03:52:15 UTC
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)
Comment 14 Jason Merrill 2011-07-25 23:58:52 UTC
I believe this is now fixed.