Improve our handling of (C++) references within Clang. Specifically:
- Do not allow expressions to ever have reference type
- Extend Expr::isLvalue to handle more cases where having written a
reference into the source implies that the expression is an lvalue
(e.g., function calls, C++ casts).
- Make GRExprEngine::VisitCall treat the call arguments as lvalues when
they are being bound to a reference parameter.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58306 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7b88ec2..3e33172 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1382,11 +1382,6 @@
if (CompoundLiteralExpr *e = dyn_cast<CompoundLiteralExpr>(Init))
return CheckForConstantInitializer(e->getInitializer(), DclT);
- if (Init->getType()->isReferenceType()) {
- // FIXME: Work out how the heck references work.
- return false;
- }
-
if (InitListExpr *Exp = dyn_cast<InitListExpr>(Init)) {
unsigned numInits = Exp->getNumInits();
for (unsigned i = 0; i < numInits; i++) {
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a73f0dd..42f9ec7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -35,10 +35,6 @@
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
- if (const ReferenceType *ref = Ty->getAsReferenceType()) {
- ImpCastExprToType(E, ref->getPointeeType()); // C++ [expr]
- Ty = E->getType();
- }
if (Ty->isFunctionType())
ImpCastExprToType(E, Context.getPointerType(Ty));
else if (Ty->isArrayType()) {
@@ -68,10 +64,6 @@
QualType Ty = Expr->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
- if (const ReferenceType *Ref = Ty->getAsReferenceType()) {
- ImpCastExprToType(Expr, Ref->getPointeeType()); // C++ [expr]
- Ty = Expr->getType();
- }
if (Ty->isPromotableIntegerType()) // C99 6.3.1.1p2
ImpCastExprToType(Expr, Context.IntTy);
else
@@ -442,11 +434,13 @@
if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
// The BlocksAttr indicates the variable is bound by-reference.
if (VD->getAttr<BlocksAttr>())
- return new BlockDeclRefExpr(VD, VD->getType(), Loc, true);
+ return new BlockDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+ Loc, true);
// Variable will be bound by-copy, make it const within the closure.
VD->getType().addConst();
- return new BlockDeclRefExpr(VD, VD->getType(), Loc, false);
+ return new BlockDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+ Loc, false);
}
// If this reference is not in a block or if the referenced variable is
// within the block, create a normal DeclRefExpr.
@@ -1674,8 +1668,15 @@
if (lhsType == rhsType)
return Compatible; // Common case: fast path an exact match.
- if (lhsType->isReferenceType() || rhsType->isReferenceType()) {
- if (Context.typesAreCompatible(lhsType, rhsType))
+ // If the left-hand side is a reference type, then we are in a
+ // (rare!) case where we've allowed the use of references in C,
+ // e.g., as a parameter type in a built-in function. In this case,
+ // just make sure that the type referenced is compatible with the
+ // right-hand side type. The caller is responsible for adjusting
+ // lhsType so that the resulting expression does not have reference
+ // type.
+ if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) {
+ if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType))
return Compatible;
return Incompatible;
}
@@ -1808,8 +1809,7 @@
// DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
// expressions that surpress this implicit conversion (&, sizeof).
//
- // Suppress this for references: C++ 8.5.3p5. FIXME: revisit when references
- // are better understood.
+ // Suppress this for references: C++ 8.5.3p5.
if (!lhsType->isReferenceType())
DefaultFunctionArrayConversion(rExpr);
@@ -1818,8 +1818,12 @@
// C99 6.5.16.1p2: The value of the right operand is converted to the
// type of the assignment expression.
+ // CheckAssignmentConstraints allows the left-hand side to be a reference,
+ // so that we can use references in built-in functions even in C.
+ // The getNonReferenceType() call makes sure that the resulting expression
+ // does not have reference type.
if (rExpr->getType() != lhsType)
- ImpCastExprToType(rExpr, lhsType);
+ ImpCastExprToType(rExpr, lhsType.getNonReferenceType());
return result;
}
@@ -2909,7 +2913,8 @@
// FIXME: Verify that MemberDecl isn't a bitfield.
// MemberDecl->getType() doesn't get the right qualifiers, but it doesn't
// matter here.
- Res = new MemberExpr(Res, false, MemberDecl, OC.LocEnd, MemberDecl->getType());
+ Res = new MemberExpr(Res, false, MemberDecl, OC.LocEnd,
+ MemberDecl->getType().getNonReferenceType());
}
return new UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(),
@@ -3121,7 +3126,8 @@
OE->getFn()->getSourceRange());
// Remember our match, and continue processing the remaining arguments
// to catch any errors.
- OE = new OverloadExpr(Args, NumArgs, i, FnType->getResultType(),
+ OE = new OverloadExpr(Args, NumArgs, i,
+ FnType->getResultType().getNonReferenceType(),
BuiltinLoc, RParenLoc);
}
}
@@ -3168,7 +3174,7 @@
// FIXME: Warn if a non-POD type is passed in.
- return new VAArgExpr(BuiltinLoc, E, T, RPLoc);
+ return new VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(), RPLoc);
}
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 34eff25..7a5e2dd 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -79,10 +79,6 @@
// C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
// [...] if a pointer to T1 can be [cast] to the type pointer to T2.
DestType = Context.getPointerType(DestTypeTmp->getPointeeType());
- if (const ReferenceType *SrcTypeTmp = SrcType->getAsReferenceType()) {
- // FIXME: This shouldn't actually be possible, but right now it is.
- SrcType = SrcTypeTmp->getPointeeType();
- }
SrcType = Context.getPointerType(SrcType);
} else {
// C++ 5.2.11p1: Otherwise, the result is an rvalue and the
@@ -177,10 +173,6 @@
// built-in & and * operators.
// This code does this transformation for the checked types.
DestType = Context.getPointerType(DestTypeTmp->getPointeeType());
- if (const ReferenceType *SrcTypeTmp = SrcType->getAsReferenceType()) {
- // FIXME: This shouldn't actually be possible, but right now it is.
- SrcType = SrcTypeTmp->getPointeeType();
- }
SrcType = Context.getPointerType(SrcType);
} else {
// C++ 5.2.10p1: [...] the lvalue-to-rvalue, array-to-pointer, and