class Expr : public Stmt {
QualType TR;
protected:
- Expr(StmtClass SC, QualType T) : Stmt(SC), TR(T) {}
+ Expr(StmtClass SC, QualType T) : Stmt(SC), TR(T) {
+ // In C++, the type of an expression is always adjusted so that it
+ // will not have reference type an expression will never have
+ // reference type (C++ [expr]p6). Use
+ // QualType::getNonReferenceType() to retrieve the non-reference
+ // type. Additionally, inspect Expr::isLvalue to determine whether
+ // an expression that is adjusted in this manner should be
+ // considered an lvalue.
+ assert((T.isNull() || !T->isReferenceType()) && "Expressions can't have reference type");
+ }
public:
QualType getType() const { return TR; }
void setType(QualType t) { TR = t; }
const Expr *getSubExpr() const { return cast<Expr>(Op); }
static bool classof(const Stmt *T) {
- switch (T->getStmtClass()) {
- case ImplicitCastExprClass:
- case ExplicitCastExprClass:
- case ExplicitCCastExprClass:
- case CXXNamedCastExprClass:
- case CXXStaticCastExprClass:
- case CXXDynamicCastExprClass:
- case CXXReinterpretCastExprClass:
- case CXXConstCastExprClass:
- case CXXFunctionalCastExprClass:
+ StmtClass SC = T->getStmtClass();
+ if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
+ return true;
+
+ if (SC >= ImplicitCastExprClass && SC <= ExplicitCCastExprClass)
return true;
- default:
- return false;
- }
+
+ return false;
}
static bool classof(const CastExpr *) { return true; }
QualType getTypeAsWritten() const { return TypeAsWritten; }
static bool classof(const Stmt *T) {
- switch (T->getStmtClass()) {
- case ExplicitCastExprClass:
- case ExplicitCCastExprClass:
- case CXXFunctionalCastExprClass:
- case CXXStaticCastExprClass:
- case CXXDynamicCastExprClass:
- case CXXReinterpretCastExprClass:
- case CXXConstCastExprClass:
+ StmtClass SC = T->getStmtClass();
+ if (SC >= ExplicitCastExprClass && SC <= ExplicitCCastExprClass)
+ return true;
+ if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
return true;
- default:
- return false;
- }
+
+ return false;
}
static bool classof(const ExplicitCastExpr *) { return true; }
};
public:
CXXConditionDeclExpr(SourceLocation startLoc,
SourceLocation eqLoc, VarDecl *var)
- : DeclRefExpr(CXXConditionDeclExprClass, var, var->getType(), startLoc) {}
+ : DeclRefExpr(CXXConditionDeclExprClass, var,
+ var->getType().getNonReferenceType(), startLoc) {}
virtual void Destroy(ASTContext& Ctx);
STMT(62, CXXDynamicCastExpr , CXXNamedCastExpr)
STMT(63, CXXReinterpretCastExpr , CXXNamedCastExpr)
STMT(64, CXXConstCastExpr , CXXNamedCastExpr)
-STMT(65, CXXBoolLiteralExpr , Expr)
-STMT(66, CXXThrowExpr , Expr)
-STMT(67, CXXDefaultArgExpr , Expr)
-STMT(68, CXXFunctionalCastExpr , Expr)
+STMT(65, CXXFunctionalCastExpr , Expr)
+STMT(66, CXXBoolLiteralExpr , Expr)
+STMT(67, CXXThrowExpr , Expr)
+STMT(68, CXXDefaultArgExpr , Expr)
STMT(69, CXXZeroInitValueExpr , Expr)
STMT(70, CXXConditionDeclExpr , DeclRefExpr)
void VisitCall(CallExpr* CE, NodeTy* Pred,
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
NodeSet& Dst);
+ void VisitCallRec(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
+ NodeSet& Dst, const FunctionTypeProto *,
+ unsigned ParamIdx = 0);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
break;
case ParenExprClass: // C99 6.5.1p5
return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
+ case CallExprClass: {
+ // C++ [expr.call]p10:
+ // A function call is an lvalue if and only if the result type
+ // is a reference.
+ QualType CalleeType
+ = dyn_cast<CallExpr>(this)->getCallee()->IgnoreParens()->getType();
+ if (const PointerType *FnTypePtr = CalleeType->getAsPointerType())
+ if (const FunctionType *FnType
+ = FnTypePtr->getPointeeType()->getAsFunctionType())
+ if (FnType->getResultType()->isReferenceType())
+ return LV_Valid;
+
+ break;
+ }
case CompoundLiteralExprClass: // C99 6.5.2.5p5
return LV_Valid;
case ExtVectorElementExprClass:
return (cast<PredefinedExpr>(this)->getIdentType()
== PredefinedExpr::CXXThis
? LV_InvalidExpression : LV_Valid);
+ case VAArgExprClass:
+ return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
case CXXConditionDeclExprClass:
return LV_Valid;
+ case ExplicitCCastExprClass:
+ case CXXFunctionalCastExprClass:
+ case CXXStaticCastExprClass:
+ case CXXDynamicCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass:
+ // The result of an explicit cast is an lvalue if the type we are
+ // casting to is a reference type. See C++ [expr.cast]p1,
+ // C++ [expr.static.cast]p2, C++ [expr.dynamic.cast]p2,
+ // C++ [expr.reinterpret.cast]p1, C++ [expr.const.cast]p1.
+ if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()->isReferenceType())
+ return LV_Valid;
+ break;
default:
break;
}
//===----------------------------------------------------------------------===//
// Transfer function: Function calls.
//===----------------------------------------------------------------------===//
-
void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
- NodeSet& Dst) {
+ NodeSet& Dst)
+{
+ // Determine the type of function we're calling (if available).
+ const FunctionTypeProto *Proto = NULL;
+ QualType FnType = CE->getCallee()->IgnoreParens()->getType();
+ if (const PointerType *FnTypePtr = FnType->getAsPointerType())
+ Proto = FnTypePtr->getPointeeType()->getAsFunctionTypeProto();
+
+ VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
+}
+
+void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator AI,
+ CallExpr::arg_iterator AE,
+ NodeSet& Dst, const FunctionTypeProto *Proto,
+ unsigned ParamIdx) {
// Process the arguments.
-
if (AI != AE) {
-
- NodeSet DstTmp;
- Visit(*AI, Pred, DstTmp);
+ // If the call argument is being bound to a reference parameter,
+ // visit it as an lvalue, not an rvalue.
+ bool VisitAsLvalue = false;
+ if (Proto && ParamIdx < Proto->getNumArgs())
+ VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
+
+ NodeSet DstTmp;
+ if (VisitAsLvalue)
+ VisitLValue(*AI, Pred, DstTmp);
+ else
+ Visit(*AI, Pred, DstTmp);
++AI;
for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
- VisitCall(CE, *DI, AI, AE, Dst);
+ VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1);
return;
}
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++) {
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()) {
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
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.
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;
}
// 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);
// 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;
}
// 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(),
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);
}
}
// 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,
// 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
// 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