lvalue-to-rvalue conversion adjusts lvalues of qualified, non-class
type to rvalue expressions of the unqualified variant of that
type. For example, given:
const int i;
(void)(i + 17);
the lvalue-to-rvalue conversion for the subexpression "i" will turn it
from an lvalue expression (a DeclRefExpr) with type 'const int' into
an rvalue expression with type 'int'. Both C and C++ mandate this
conversion, and somehow we've slid through without implementing it.
We now have both DefaultFunctionArrayConversion and
DefaultFunctionArrayLvalueConversion, and which gets used depends on
whether we do the lvalue-to-rvalue conversion or not. Generally, we do
the lvalue-to-rvalue conversion, but there are a few notable
exceptions:
- the left-hand side of a '.' operator
- the left-hand side of an assignment
- a C++ throw expression
- a subscript expression that's subscripting a vector
Making this change exposed two issues with blocks:
- we were deducing const-qualified return types of non-class type
from a block return, which doesn't fit well
- we weren't always setting the known return type of a block when it
was provided with the ^return-type syntax
Fixes the current Clang-on-Clang compile failure and PR6076.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95167
91177308-0d34-0410-b5e6-
96231b3b80d8
// to their respective pointers (C99 6.3.2.1).
void DefaultFunctionArrayConversion(Expr *&expr);
+ // DefaultFunctionArrayLvalueConversion - converts functions and
+ // arrays to their respective pointers and performs the
+ // lvalue-to-rvalue conversion.
+ void DefaultFunctionArrayLvalueConversion(Expr *&expr);
+
// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
// do not have a prototype. Integer promotions are performed on each
// argument, and arguments that have type float are promoted to double.
CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, const SourceRange &DestRange) {
if (!DestType->isLValueReferenceType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
const SourceRange &OpRange, const SourceRange &DestRange,
CastExpr::CastKind &Kind) {
if (!DestType->isLValueReferenceType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
}
if (!DestType->isLValueReferenceType() && !DestType->isRecordType())
- Self.DefaultFunctionArrayConversion(SrcExpr);
+ Self.DefaultFunctionArrayLvalueConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
return false;
if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType())
- DefaultFunctionArrayConversion(CastExpr);
+ DefaultFunctionArrayLvalueConversion(CastExpr);
// C++ [expr.cast]p5: The conversions performed by
// - a const_cast,
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayConversion(RecExpr);
+ DefaultFunctionArrayLvalueConversion(RecExpr);
QualType ReceiverType = RecExpr->getType();
if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
}
}
+void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) {
+ DefaultFunctionArrayConversion(E);
+
+ QualType Ty = E->getType();
+ assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type");
+ if (!Ty->isDependentType() && Ty.hasQualifiers() &&
+ (!getLangOptions().CPlusPlus || !Ty->isRecordType()) &&
+ E->isLvalue(Context) == Expr::LV_Valid) {
+ // C++ [conv.lval]p1:
+ // [...] If T is a non-class type, the type of the rvalue is the
+ // cv-unqualified version of T. Otherwise, the type of the
+ // rvalue is T
+ //
+ // C99 6.3.2.1p2:
+ // If the lvalue has qualified type, the value has the unqualified
+ // version of the type of the lvalue; otherwise, the value has the
+ // type of the lvalue.
+ ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp);
+ }
+}
+
+
/// UsualUnaryConversions - Performs various conversions that are common to most
/// operators (C99 6.3). The conversions of array and function types are
/// sometimes surpressed. For example, the array->pointer conversion doesn't
return Expr;
}
- DefaultFunctionArrayConversion(Expr);
+ DefaultFunctionArrayLvalueConversion(Expr);
return Expr;
}
Expr *RHSExp = static_cast<Expr*>(Idx.get());
// Perform default conversions.
- DefaultFunctionArrayConversion(LHSExp);
- DefaultFunctionArrayConversion(RHSExp);
+ if (!LHSExp->getType()->getAs<VectorType>())
+ DefaultFunctionArrayLvalueConversion(LHSExp);
+ DefaultFunctionArrayLvalueConversion(RHSExp);
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
ResultType = VTy->getElementType();
} else if (LHSTy->isArrayType()) {
// If we see an array that wasn't promoted by
- // DefaultFunctionArrayConversion, it must be an array that
+ // DefaultFunctionArrayLvalueConversion, it must be an array that
// wasn't promoted because of the C90 rule that doesn't
// allow promoting non-lvalue arrays. Warn, then
// force the promotion here.
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
ConversionDecl);
- DefaultFunctionArrayConversion(castExpr);
+ DefaultFunctionArrayLvalueConversion(castExpr);
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
//
// Suppress this for references: C++ 8.5.3p5.
if (!lhsType->isReferenceType())
- DefaultFunctionArrayConversion(rExpr);
+ DefaultFunctionArrayLvalueConversion(rExpr);
Sema::AssignConvertType result =
CheckAssignmentConstraints(lhsType, rExpr->getType());
// C99 6.5.17
QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
// Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions.
- DefaultFunctionArrayConversion(RHS);
+ // C++ does not perform this conversion (C++ [expr.comma]p1).
+ if (!getLangOptions().CPlusPlus)
+ DefaultFunctionArrayLvalueConversion(RHS);
// FIXME: Check that RHS type is complete in C mode (it's legal for it to be
// incomplete in C++).
resultType = CheckAddressOfOperand(Input, OpLoc);
break;
case UnaryOperator::Deref:
- DefaultFunctionArrayConversion(Input);
+ DefaultFunctionArrayLvalueConversion(Input);
resultType = CheckIndirectionOperand(Input, OpLoc);
break;
case UnaryOperator::Plus:
break;
case UnaryOperator::LNot: // logical negation
// Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
- DefaultFunctionArrayConversion(Input);
+ DefaultFunctionArrayLvalueConversion(Input);
resultType = Input->getType();
if (resultType->isDependentType())
break;
// Promote the array so it looks more like a normal array subscript
// expression.
- DefaultFunctionArrayConversion(Res);
+ DefaultFunctionArrayLvalueConversion(Res);
// C99 6.5.2.1p1
Expr *Idx = static_cast<Expr*>(OC.U.E);
diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy;
return;
}
+
+ CurBlock->ReturnType = RetTy;
return;
}
DiagnoseAssignmentAsCondition(E);
if (!E->isTypeDependent()) {
- DefaultFunctionArrayConversion(E);
+ DefaultFunctionArrayLvalueConversion(E);
QualType T = E->getType();
if (LVoid || RVoid) {
// ... then the [l2r] conversions are performed on the second and third
// operands ...
- DefaultFunctionArrayConversion(LHS);
- DefaultFunctionArrayConversion(RHS);
+ DefaultFunctionArrayLvalueConversion(LHS);
+ DefaultFunctionArrayLvalueConversion(RHS);
LTy = LHS->getType();
RTy = RHS->getType();
// C++0x 5.16p6
// LValue-to-rvalue, array-to-pointer, and function-to-pointer standard
// conversions are performed on the second and third operands.
- DefaultFunctionArrayConversion(LHS);
- DefaultFunctionArrayConversion(RHS);
+ DefaultFunctionArrayLvalueConversion(LHS);
+ DefaultFunctionArrayLvalueConversion(RHS);
LTy = LHS->getType();
RTy = RHS->getType();
// If necessary, apply function/array conversion to the receiver.
// C99 6.7.5.3p[7,8].
- DefaultFunctionArrayConversion(RExpr);
+ DefaultFunctionArrayLvalueConversion(RExpr);
QualType returnType;
QualType ReceiverCType =
<< FirstType << First->getSourceRange();
}
if (Second) {
- DefaultFunctionArrayConversion(Second);
+ DefaultFunctionArrayLvalueConversion(Second);
QualType SecondType = Second->getType();
if (!SecondType->isObjCObjectPointerType())
Diag(ForLoc, diag::err_collection_expr_type)
if (RetValExp) {
// Don't call UsualUnaryConversions(), since we don't want to do
// integer promotions here.
- DefaultFunctionArrayConversion(RetValExp);
+ DefaultFunctionArrayLvalueConversion(RetValExp);
CurBlock->ReturnType = RetValExp->getType();
if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
// We have to remove a 'const' added to copied-in variable which was
}
}
- DefaultFunctionArrayConversion(Exprs[i]);
+ DefaultFunctionArrayLvalueConversion(Exprs[i]);
InputConstraintInfos.push_back(Info);
}
void foo7()
{
- const int (^BB) (void) = ^{ const int i = 1; return i; }; // OK
+ const int (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int (^)(void)', expected 'int const (^)(void)'}}
const int (^CC) (void) = ^const int{ const int i = 1; return i; }; // OK
int i;
__block const int k;
const int cint = 100;
- int (^MM) (void) = ^{ return k; }; // expected-error {{incompatible block pointer types initializing 'int const (^)(void)', expected 'int (^)(void)'}}
- int (^NN) (void) = ^{ return cint; }; // expected-error {{incompatible block pointer types initializing 'int const (^)(void)', expected 'int (^)(void)'}}
-
+ int (^MM) (void) = ^{ return k; };
+ int (^NN) (void) = ^{ return cint; };
}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR6076
+void f();
+void (&g)() = (void(), f);
+
+int a[1];
+int (&b)[1] = (void(), a);
enum { id };
};
}
+
+namespace Conditional {
+ enum a { A }; a x(const enum a x) { return 1?x:A; }
+}
// Invalid: T1 const* -> T2*
(void)reinterpret_cast<int*>(icp); // expected-error {{reinterpret_cast from 'int const *' to 'int *' casts away constness}}
// Invalid: T1*** -> T2 const* const**
- int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***const' to 'int const *const **' casts away constness}}
+ int const *const **icpcpp = reinterpret_cast<int const* const**>(ipppc); // expected-error {{reinterpret_cast from 'int ***' to 'int const *const **' casts away constness}}
// Valid: T1* -> T2*
int *ip = reinterpret_cast<int*>(icpcpp);
// Valid: T* -> T const*