diff options
-rw-r--r-- | include/clang/AST/Expr.h | 48 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 3 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 8 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRExprEngine.h | 4 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 29 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 8 |
9 files changed, 114 insertions, 68 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 70a768171e..79cb76012e 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -38,7 +38,16 @@ namespace clang { 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 @@ public: 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 @@ public: 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; } }; diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index ef5f95d09c..61d25e9a97 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -301,7 +301,8 @@ class CXXConditionDeclExpr : public DeclRefExpr { 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); diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index a79639eac0..a1403915c9 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -95,10 +95,10 @@ STMT(61, CXXStaticCastExpr , CXXNamedCastExpr) 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) diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 22454810be..802b07e31f 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -495,6 +495,10 @@ protected: 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); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1380264e0e..f330444f1d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -393,6 +393,20 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { 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 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { 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; } diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index e843f5d9e1..41579ac3a7 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -1063,22 +1063,43 @@ const GRState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred, //===----------------------------------------------------------------------===// // 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; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7b88ec2c16..3e33172c8a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1382,11 +1382,6 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { 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 a73f0dde0a..42f9ec727e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -35,10 +35,6 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { 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 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) { 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 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, 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 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { 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 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // 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 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&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; } @@ -2909,7 +2913,8 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, // 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 @@ Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs, 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 @@ Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, // 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 34eff25b4c..7a5e2dd4e9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -79,10 +79,6 @@ Sema::CheckConstCast(SourceLocation OpLoc, Expr *&SrcExpr, QualType DestType) // 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 @@ Sema::CheckReinterpretCast(SourceLocation OpLoc, Expr *&SrcExpr, // 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 |