66297: C++14 removed the requirement that a constexpr member function must be a member of a literal class.
70979: We were failing to treat a C++14 lambda as non-literal; they are only literal with the constexpr lambda addition in C++17. Tested x86_64-pc-linux-gnu, applying to trunk.
commit 187ea37ce9cc03f4c9940b007de65d17ad94e777 Author: Jason Merrill <ja...@redhat.com> Date: Mon Feb 13 15:39:12 2017 -0500 PR c++/66297, DR 1684 - literal class and constexpr member fns * constexpr.c (is_valid_constexpr_fn): Only complain about non-literal enclosing class in C++11. * class.c (finalize_literal_type_property): Likewise. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 9b996e3..89fa822 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5757,7 +5757,9 @@ finalize_literal_type_property (tree t) && !TYPE_HAS_CONSTEXPR_CTOR (t)) CLASSTYPE_LITERAL_P (t) = false; - if (!CLASSTYPE_LITERAL_P (t)) + /* C++14 DR 1684 removed this restriction. */ + if (cxx_dialect < cxx14 + && !CLASSTYPE_LITERAL_P (t) && !LAMBDA_TYPE_P (t)) for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn)) if (DECL_DECLARED_CONSTEXPR_P (fn) && TREE_CODE (fn) != TEMPLATE_DECL @@ -5765,12 +5767,11 @@ finalize_literal_type_property (tree t) && !DECL_CONSTRUCTOR_P (fn)) { DECL_DECLARED_CONSTEXPR_P (fn) = false; - if (!DECL_GENERATED_P (fn) && !LAMBDA_TYPE_P (t)) - { - error ("enclosing class of constexpr non-static member " - "function %q+#D is not a literal type", fn); - explain_non_literal_class (t); - } + if (!DECL_GENERATED_P (fn) + && pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic, + "enclosing class of constexpr non-static member " + "function %q+#D is not a literal type", fn)) + explain_non_literal_class (t); } } diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 34d25ba..157b20d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -210,16 +210,17 @@ is_valid_constexpr_fn (tree fun, bool complain) } } - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) + /* C++14 DR 1684 removed this restriction. */ + if (cxx_dialect < cxx14 + && DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun))) { ret = false; - if (complain) - { - error ("enclosing class of constexpr non-static member " - "function %q+#D is not a literal type", fun); - explain_non_literal_class (DECL_CONTEXT (fun)); - } + if (complain + && pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic, + "enclosing class of constexpr non-static member " + "function %q+#D is not a literal type", fun)) + explain_non_literal_class (DECL_CONTEXT (fun)); } } else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun))) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C index f49c56a..9078533 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-data1.C @@ -36,7 +36,7 @@ class debug_flag { public: explicit debug_flag(bool); - constexpr bool is_on(); // { dg-error "enclosing class .* not a literal type" } + constexpr bool is_on(); // { dg-error "enclosing class .* not a literal type" "" { target c++11_only } } private: bool flag; }; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C index 6b908b6..450a0b5 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C @@ -5,7 +5,7 @@ template <class T> struct A { T t; - constexpr int f() const { return 42; } // { dg-error "enclosing class" } + constexpr int f() const { return 42; } // { dg-error "enclosing class" "" { target c++11_only } } }; struct B { B(); operator int(); }; @@ -13,7 +13,7 @@ struct B { B(); operator int(); }; constexpr A<int> ai = { 42 }; constexpr int i = ai.f(); -constexpr int b = A<B>().f(); // { dg-error "non-constexpr function" } +constexpr int b = A<B>().f(); // { dg-error "" } template <class T> constexpr int f (T t) { return 42; } // { dg-error "parameter" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C index 580fceb..27aad93 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C @@ -16,7 +16,7 @@ int main() struct complex // { dg-message "no constexpr constructor" } { complex(double r, double i) : re(r), im(i) { } - constexpr double real() const { return re; } // { dg-error "not a literal type" } + constexpr double real() const { return re; } // { dg-error "not a literal type" "" { target c++11_only } } double imag() const { return im; } private: @@ -25,7 +25,7 @@ private: }; constexpr complex co1(0, 1); // { dg-error "not literal" } -constexpr double dd2 = co1.real(); // { dg-error "non-constexpr function" } +constexpr double dd2 = co1.real(); // { dg-error "" } // -------------------- diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C index 775c103..d59f465 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C @@ -13,6 +13,6 @@ constexpr X X::g(X x) { return x; } struct Y { Y() { } - constexpr Y f(Y y); // { dg-error "not a literal type" } + constexpr Y f(Y y) {} // { dg-error "constexpr" } static constexpr Y g(Y y) {} // { dg-error "constexpr" } }; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C index 58b5d32..9c832b1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C @@ -45,7 +45,7 @@ constexpr int g(int x, int n) { class debug_flag { public: explicit debug_flag(bool); - constexpr bool is_on(); // { dg-error "not a literal type" } debug_flag not literal type + constexpr bool is_on(); // { dg-error "not a literal type" "" { target c++11_only } } debug_flag not literal type private: bool flag; }; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-dr1684.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-dr1684.C new file mode 100644 index 0000000..04ffcfd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-dr1684.C @@ -0,0 +1,7 @@ +// DR 1684 +// { dg-do compile { target c++11 } } + +struct A { + A(int); + constexpr int foo() { return 0; } // { dg-error "literal" "" { target c++11_only } } +};
commit fcb0b94da309fac966bf70eec9080ed4f4e10adf Author: Jason Merrill <ja...@redhat.com> Date: Mon Feb 13 15:43:15 2017 -0500 PR c++/70979 - literal class and closure types * class.c (finalize_literal_type_property): Handle closures specifically. (explain_non_literal_class): Likewise. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 89fa822..fc71766 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5752,6 +5752,8 @@ finalize_literal_type_property (tree t) if (cxx_dialect < cxx11 || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) CLASSTYPE_LITERAL_P (t) = false; + else if (CLASSTYPE_LITERAL_P (t) && LAMBDA_TYPE_P (t)) + CLASSTYPE_LITERAL_P (t) = (cxx_dialect >= cxx1z); else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t) && CLASSTYPE_NON_AGGREGATE (t) && !TYPE_HAS_CONSTEXPR_CTOR (t)) @@ -5794,10 +5796,14 @@ explain_non_literal_class (tree t) return; inform (0, "%q+T is not literal because:", t); - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) + if (cxx_dialect < cxx1z && LAMBDA_TYPE_P (t)) + inform (0, " %qT is a closure type, which is only literal in " + "C++1z and later", t); + else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) inform (0, " %q+T has a non-trivial destructor", t); else if (CLASSTYPE_NON_AGGREGATE (t) && !TYPE_HAS_TRIVIAL_DFLT (t) + && !LAMBDA_TYPE_P (t) && !TYPE_HAS_CONSTEXPR_CTOR (t)) { inform (0, " %q+T is not an aggregate, does not have a trivial " diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda15.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda15.C index 7e05481..358d4aa 100644 --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda15.C +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda15.C @@ -1,9 +1,9 @@ // PR c++/79461 -// { dg-options -std=c++1z } +// { dg-do compile { target c++14 } } struct S { constexpr S(int i) { - auto f = [i]{}; + auto f = [i]{}; // { dg-error "literal" "" { target c++14_only } } } }; int main() {}