[cfe-commits] r161450 - in /cfe/trunk: lib/Sema/SemaExprCXX.cpp test/SemaCXX/constant-expression-cxx11.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Tue Aug 7 15:06:48 PDT 2012
Author: rsmith
Date: Tue Aug 7 17:06:48 2012
New Revision: 161450
URL: http://llvm.org/viewvc/llvm-project?rev=161450&view=rev
Log:
When building a conditional operator where one operand is a throw-expression
and the other is a glvalue of class type, don't forget to copy-initialize a
temporary when performing the lvalue-to-rvalue conversion on the glvalue.
Strangely, DefaultLvalueConversions misses this part of the lvalue-to-rvalue
conversions.
Modified:
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=161450&r1=161449&r2=161450&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Aug 7 17:06:48 2012
@@ -4106,7 +4106,7 @@
// FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
// interface pointers.
- // C++0x 5.16p1
+ // C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
if (!Cond.get()->isTypeDependent()) {
ExprResult CondRes = CheckCXXBooleanCondition(Cond.take());
@@ -4123,7 +4123,7 @@
if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
return Context.DependentTy;
- // C++0x 5.16p2
+ // C++11 [expr.cond]p2
// If either the second or the third operand has type (cv) void, ...
QualType LTy = LHS.get()->getType();
QualType RTy = RHS.get()->getType();
@@ -4136,12 +4136,26 @@
RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+
+ // Finish off the lvalue-to-rvalue conversion by copy-initializing a
+ // temporary if necessary. DefaultFunctionArrayLvalueConversion doesn't
+ // do this part for us.
+ ExprResult &NonVoid = LVoid ? RHS : LHS;
+ if (NonVoid.get()->getType()->isRecordType() &&
+ NonVoid.get()->isGLValue()) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(NonVoid.get()->getType());
+ NonVoid = PerformCopyInitialization(Entity, SourceLocation(), NonVoid);
+ if (NonVoid.isInvalid())
+ return QualType();
+ }
+
LTy = LHS.get()->getType();
RTy = RHS.get()->getType();
// ... and one of the following shall hold:
// -- The second or the third operand (but not both) is a throw-
- // expression; the result is of the type of the other and is an rvalue.
+ // expression; the result is of the type of the other and is a prvalue.
bool LThrow = isa<CXXThrowExpr>(LHS.get());
bool RThrow = isa<CXXThrowExpr>(RHS.get());
if (LThrow && !RThrow)
@@ -4150,7 +4164,7 @@
return LTy;
// -- Both the second and third operands have type void; the result is of
- // type void and is an rvalue.
+ // type void and is a prvalue.
if (LVoid && RVoid)
return Context.VoidTy;
@@ -4167,6 +4181,10 @@
// Otherwise, if the second and third operand have different types, and
// either has (cv) class type, and attempt is made to convert each of those
// operands to the other.
+ //
+ // FIXME: In C++11, if both operands have the same value category and the same
+ // type except for cv-qualification, the types are unified. This is valid:
+ // volatile int a; int b; volatile int &c = x ? a : b;
if (!Context.hasSameType(LTy, RTy) &&
(LTy->isRecordType() || RTy->isRecordType())) {
ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=161450&r1=161449&r2=161450&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Aug 7 17:06:48 2012
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -fsyntax-only -verify -std=c++11 -pedantic %s -Wno-comment
+// RUN: %clang_cc1 -triple i686-linux -Wno-string-plus-int -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment
namespace StaticAssertFoldTest {
@@ -1294,9 +1294,9 @@
// Constructors can be implicitly constexpr, even for a non-literal type.
namespace ImplicitConstexpr {
struct Q { Q() = default; Q(const Q&) = default; Q(Q&&) = default; ~Q(); }; // expected-note 3{{here}}
- struct R { constexpr R(); constexpr R(const R&); constexpr R(R&&); ~R(); };
+ struct R { constexpr R() noexcept; constexpr R(const R&) noexcept; constexpr R(R&&) noexcept; ~R() noexcept; };
struct S { R r; }; // expected-note 3{{here}}
- struct T { T(const T&); T(T &&); ~T(); };
+ struct T { T(const T&) noexcept; T(T &&) noexcept; ~T() noexcept; };
struct U { T t; }; // expected-note 3{{here}}
static_assert(!__is_literal_type(Q), "");
static_assert(!__is_literal_type(R), "");
@@ -1351,3 +1351,20 @@
static_assert(x[1].m == 5, "");
static_assert(x[2].m == 6, "");
}
+
+// Indirectly test that an implicit lvalue-to-rvalue conversion is performed
+// when a conditional operator has one argument of type void and where the other
+// is a glvalue of class type.
+namespace ConditionalLValToRVal {
+ struct A {
+ constexpr A(int a) : v(a) {}
+ int v;
+ };
+
+ constexpr A f(const A &a) {
+ return a.v == 0 ? throw a : a;
+ }
+
+ constexpr A a(4);
+ static_assert(f(a).v == 4, "");
+}
More information about the cfe-commits
mailing list