[cfe-commits] r58306 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def include/clang/Analysis/PathSensitive/GRExprEngine.h lib/AST/Expr.cpp lib/Analysis/GRExprEngine.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp
Douglas Gregor
doug.gregor at gmail.com
Mon Oct 27 17:22:11 PDT 2008
Author: dgregor
Date: Mon Oct 27 19:22:11 2008
New Revision: 58306
URL: http://llvm.org/viewvc/llvm-project?rev=58306&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/AST/StmtNodes.def
cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Analysis/GRExprEngine.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon Oct 27 19:22:11 2008
@@ -38,7 +38,16 @@
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; }
@@ -786,20 +795,14 @@
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; }
@@ -862,18 +865,13 @@
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; }
};
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Mon Oct 27 19:22:11 2008
@@ -301,7 +301,8 @@
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);
Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Mon Oct 27 19:22:11 2008
@@ -95,10 +95,10 @@
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)
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Mon Oct 27 19:22:11 2008
@@ -495,6 +495,10 @@
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);
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon Oct 27 19:22:11 2008
@@ -393,6 +393,20 @@
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:
@@ -407,10 +421,25 @@
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;
}
Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Mon Oct 27 19:22:11 2008
@@ -1063,22 +1063,43 @@
//===----------------------------------------------------------------------===//
// 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;
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Oct 27 19:22:11 2008
@@ -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++) {
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Oct 27 19:22:11 2008
@@ -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,
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=58306&r1=58305&r2=58306&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Oct 27 19:22:11 2008
@@ -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
More information about the cfe-commits
mailing list