7

But it compiles in gcc 4.9.0. See live example:

#include <iostream>
struct A {
    constexpr A(): i(5) {}
    int&& f() { return std::move(i); }
    int i;
} a;

A&& f(A& a) { return std::move(a); } 

int main() {
    A a;
    int b[a.f()]{ 0, 1, 2, 3, 4 };
    std::cout << b[4] << '\n';
}

From §5.19/3 we have:

An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. [ Note: Such expressions may be used as array bounds (8.3.4, 5.3.4), as bit-field lengths (9.6), as enumerator initializers if the underlying type is not fixed (7.2), and as alignments (7.6.2). —end note]

The expression a.f()is an expression of integral type. It seems to me (although I need some clarification on this point) that this expression is also convertible to a prvalue, because it is an xvalue. But I think the real problem here is that the expression a.f() is not a core constant expression, as it satisfies bullet point (2.1) in §5.19/2.

§5.19/2:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:

(2.1) — this (5.1.1), except in a constexpr function or a constexpr constructor that is being evaluated as part of e;

Ayrosa
  • 3,385
  • 1
  • 18
  • 29
  • 1
    If you try compiling this with clang++, it points out that "variable size arrays not allowed" - so I have a feeling that gcc just isn't being pedantic enough. – Mats Petersson Dec 20 '15 at 13:04
  • Convincing GCC to enforce compliance can be a pain. I found compiling with the flag `--pedantic-errors` seems to do the trick. I would favour strict conformance as the default and flags to turn conformance off. – Galik Dec 20 '15 at 13:08
  • Does that site enable strict conformance mode on the compiler (I'm too lazy to figure out what scripts/third party sites to enable to see it for myself)? If not, the reason is that g++ has a non-standard extension for automatic storage duration arrays with non-constant size. – celtschk Dec 20 '15 at 13:09
  • @MatsPetersson `clang` seems to have a bug, in that it still doesn't accept §5.19/3. For instance, it doesn't compile the code in this [other question of mine](http://stackoverflow.com/q/34360286/411165), even though that seems to be a valid code. – Ayrosa Dec 20 '15 at 13:10
  • Anyway, make sure you use strict language compliance flags. – juanchopanza Dec 20 '15 at 13:11

2 Answers2

7

You're correct, a.f() is not a constant expression. And variable length arrays are not allowed by the c++ standard. The GNU compiler, however, supports them as a language extension. You can ask the compiler to give you a warning when you use non-standard extensions with the -pedantic option, or an error with -pedantic-errors.

Edit: Apparently, GCC 4.9 added the official support for N3639, the proposal to add variable length arrays to the C++14 standard. In the end, the proposal was not included in the standard, but GCC 4.9 was released before C++14, so that change was not reflected. So, VLA's are supported by GCC 4.9 on purpose in C++14 mode and the above options don't disable them. Note that the C++14 mode is still experimental (even in GCC 5).

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • There are no error messages with `-pedantic-errors`, nor warnings with `-pedantic` – Ayrosa Dec 20 '15 at 13:16
  • Would you say that this is also a variable length array? `struct A { operator int() { return 5; } } a; int main() { int b[a]{ 0, 1, 2, 3, 4 }; }` – Ayrosa Dec 20 '15 at 13:22
  • 1
    @Ayrosa hmm, I tried it out and apparently there is no warning/error when compiled with `-std=c++14` using g++-4.9.2, but there is when compiled with `-std=c++11`. The warning works in c++14 with g++-5.2.0. This might be a compiler bug and apparently fixed. – eerorika Dec 20 '15 at 13:22
  • But this is reasonable, as these rules, §5.19/2 and /3, were changed or didn't exist in C++11. Take a look at the snippet in my prior comment. It's a perfectly legal code in C++14, and gcc 4.9.0 compiles it correctly. – Ayrosa Dec 20 '15 at 13:26
  • 1
    GCC is not known for its standard conformance, though it's gradually improving on that. – edmz Dec 20 '15 at 13:26
  • @user2079303 `yes, that expression isn't constant either.` This code is perfectly legal according to §5.19.3 and §5.19.2. See this [other question](http://stackoverflow.com/q/34360286/411165). – Ayrosa Dec 20 '15 at 13:27
  • @Ayrosa I think, it is not. The conversion function in your class A has not been declared with `constexpr` _decl-specifier_, so... – Eugene Zavidovsky Dec 20 '15 at 13:30
  • @Ayrosa I took my comment back, I don't think I grasp the rules exactly. But g++ does consider it a vla. – eerorika Dec 20 '15 at 13:33
  • @EugeneZavidovsky You may have a point here! The issue is probably more confusing than I thought. – Ayrosa Dec 20 '15 at 13:36
  • 1
    @Ayrosa I did some searching for why VLA's are allowed even with `-pedantic`. See my edit. – eerorika Dec 20 '15 at 13:44
  • @user2079303 I wonder how many new kinds of vulnerabilities in programs that change (N3639) to the Standard would bring. – Eugene Zavidovsky Dec 20 '15 at 14:01
2

The following non-standard code

int x = std::rand();
int r[x] = { 1,2,3 };

compiles under g++, not because g++ mistakenly treats std::rand() as a constant expression, but because it implements VLAs by default. Use -pedantic or -Wvla to warn about them, -Werror=vla to turn these warnings into errors.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 1
    However, the error doesn't show when I use `-pedantic` in my code above. – Ayrosa Dec 20 '15 at 13:39
  • 1
    @Ayrosa Perhaps that's because 4.9 is relatively old. It does show in 5.2. – n. m. could be an AI Dec 20 '15 at 13:43
  • If I change the function `f` to be `constexpr` in my code above, `5.2` still shows an error, but now I believe the code is legal, because of §5.19/2 and §5.19/3. – Ayrosa Dec 20 '15 at 13:50
  • 1
    That's an entirely different issue. – n. m. could be an AI Dec 20 '15 at 13:56
  • I'm sorry. The code doesn't show an error in 5.2, but the warning is still [there](https://goo.gl/cuHIWb). Could you explain why? I'm not very familiar with the gcc compiler. – Ayrosa Dec 20 '15 at 15:02
  • The standard doesn't have warnings and errors, but diagnostics. What constitutes a diagnostic is implementation-defined. You need to consult the "implementation-defined behavior" section of the gcc documentation to find out. (Hint: warnings are in). That's language lawyering 101 by the way – n. m. could be an AI Dec 20 '15 at 15:08
  • `That's language lawyering 101 by default` I was not talking about the Standard, but about the compiler, and you understood this pretty well. – Ayrosa Dec 20 '15 at 15:13
  • What's the problem with the compiler? It gives you the diagnostic when in maximal confirmance mode (-pedantic). Looks fantastic to me. – n. m. could be an AI Dec 20 '15 at 15:50
  • @Ayrosa : `a` inside of `main` is not `constexpr`; why would operations on a non-constexpr object be constexpr? Also, why do you keep returning rvalue references everywhere? This is asking for dangling references and serves no purpose otherwise. – ildjarn Dec 30 '15 at 06:25