[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