[cfe-commits] r65529 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaTemplate/fun-template-def.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Thu Feb 26 06:40:00 PST 2009


Author: cornedbee
Date: Thu Feb 26 08:39:58 2009
New Revision: 65529

URL: http://llvm.org/viewvc/llvm-project?rev=65529&view=rev
Log:
Make more AST nodes and semantic checkers dependent-expression-aware.

Added:
    cfe/trunk/test/SemaTemplate/fun-template-def.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/lib/AST/ExprCXX.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=65529&r1=65528&r2=65529&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Thu Feb 26 08:39:58 2009
@@ -680,8 +680,12 @@
   SizeOfAlignOfExpr(bool issizeof, bool istype, void *argument,
                     QualType resultType, SourceLocation op,
                     SourceLocation rp) :
-      Expr(SizeOfAlignOfExprClass, resultType), isSizeof(issizeof),
-      isType(istype), OpLoc(op), RParenLoc(rp) {
+      Expr(SizeOfAlignOfExprClass, resultType,
+           false, // Never type-dependent.
+           // Value-dependent if the argument is type-dependent.
+           (istype ? QualType::getFromOpaquePtr(argument)->isDependentType()
+                   : static_cast<Expr*>(argument)->isTypeDependent())),
+      isSizeof(issizeof), isType(istype), OpLoc(op), RParenLoc(rp) {
     if (isType)
       Argument.Ty = argument;
     else
@@ -742,7 +746,10 @@
 public:
   ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t,
                      SourceLocation rbracketloc)
-  : Expr(ArraySubscriptExprClass, t), RBracketLoc(rbracketloc) {
+  : Expr(ArraySubscriptExprClass, t,
+         lhs->isTypeDependent() || rhs->isTypeDependent(),
+         lhs->isValueDependent() || rhs->isValueDependent()),
+    RBracketLoc(rbracketloc) {
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
   }

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=65529&r1=65528&r2=65529&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Feb 26 08:39:58 2009
@@ -227,12 +227,18 @@
 
 public:
   CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) :
-      Expr(CXXTypeidExprClass, Ty), isTypeOp(isTypeOp), Range(r) {
+      Expr(CXXTypeidExprClass, Ty,
+        // typeid is never type-dependent (C++ [temp.dep.expr]p4)
+        false,
+        // typeid is value-dependent if the type or expression are dependent
+        (isTypeOp ? QualType::getFromOpaquePtr(op)->isDependentType()
+                  : static_cast<Expr*>(op)->isValueDependent())),
+      isTypeOp(isTypeOp), Range(r) {
     if (isTypeOp)
       Operand.Ty = op;
     else
       // op was an Expr*, so cast it back to that to be safe
-      Operand.Ex = static_cast<Stmt*>(op);
+      Operand.Ex = static_cast<Expr*>(op);
   }
 
   bool isTypeOperand() const { return isTypeOp; }
@@ -277,7 +283,11 @@
 
 public:
   CXXThisExpr(SourceLocation L, QualType Type) 
-    : Expr(CXXThisExprClass, Type), Loc(L) { }
+    : Expr(CXXThisExprClass, Type,
+           // 'this' is type-dependent if the class type of the enclosing
+           // member function is dependent (C++ [temp.dep.expr]p2)
+           Type->isDependentType(), Type->isDependentType()),
+      Loc(L) { }
 
   virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
 
@@ -306,7 +316,7 @@
   // exepression.  The l is the location of the throw keyword.  expr
   // can by null, if the optional expression to throw isn't present.
   CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) :
-    Expr(CXXThrowExprClass, Ty), Op(expr), ThrowLoc(l) {}
+    Expr(CXXThrowExprClass, Ty, false, false), Op(expr), ThrowLoc(l) {}
   const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); }
   Expr *getSubExpr() { return cast_or_null<Expr>(Op); }
 
@@ -578,7 +588,8 @@
              Stmt **subExprs, FunctionDecl *operatorNew,
              FunctionDecl *operatorDelete, CXXConstructorDecl *constructor,
              SourceLocation startLoc, SourceLocation endLoc)
-    : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
+    : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()),
+      GlobalNew(globalNew), ParenTypeId(parenTypeId),
       Initializer(initializer), Array(array), NumPlacementArgs(numPlaceArgs),
       NumConstructorArgs(numConsArgs), SubExprs(subExprs),
       OperatorNew(operatorNew), OperatorDelete(operatorDelete),
@@ -698,7 +709,7 @@
 public:
   CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
                 FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc)
-    : Expr(CXXDeleteExprClass, ty), GlobalDelete(globalDelete),
+    : Expr(CXXDeleteExprClass, ty, false, false), GlobalDelete(globalDelete),
       ArrayForm(arrayForm), OperatorDelete(operatorDelete), Argument(arg),
       Loc(loc) { }
 

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=65529&r1=65528&r2=65529&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Thu Feb 26 08:39:58 2009
@@ -95,7 +95,8 @@
                        Expr **constructorArgs, unsigned numConsArgs,
                        FunctionDecl *operatorDelete, QualType ty,
                        SourceLocation startLoc, SourceLocation endLoc)
-  : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
+  : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()),
+    GlobalNew(globalNew), ParenTypeId(parenTypeId),
     Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs),
     NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
     OperatorDelete(operatorDelete), Constructor(constructor),

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=65529&r1=65528&r2=65529&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Feb 26 08:39:58 2009
@@ -1159,10 +1159,13 @@
 
 /// The UsualUnaryConversions() function is *not* called by this routine.
 /// See C99 6.3.2.1p[2-4] for more details.
-bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, 
+bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
                                      SourceLocation OpLoc,
                                      const SourceRange &ExprRange,
                                      bool isSizeof) {
+  if (exprType->isDependentType())
+    return false;
+
   // C99 6.5.3.4p1:
   if (isa<FunctionType>(exprType)) {
     // alignof(function) is allowed.
@@ -1186,11 +1189,15 @@
 bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
                             const SourceRange &ExprRange) {
   E = E->IgnoreParens();
-  
+
   // alignof decl is always ok. 
   if (isa<DeclRefExpr>(E))
     return false;
-  
+
+  // Cannot know anything else if the expression is dependent.
+  if (E->isTypeDependent())
+    return false;
+
   if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
     if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
       if (FD->isBitField()) {
@@ -1252,6 +1259,9 @@
 }
 
 QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
+  if (V->isTypeDependent())
+    return Context.DependentTy;
+
   DefaultFunctionArrayConversion(V);
   
   // These operators return the element type of a complex type.
@@ -1504,7 +1514,11 @@
   // and index from the expression types.
   Expr *BaseExpr, *IndexExpr;
   QualType ResultType;
-  if (const PointerType *PTy = LHSTy->getAsPointerType()) {
+  if (LHSTy->isDependentType() || RHSTy->isDependentType()) {
+    BaseExpr = LHSExp;
+    IndexExpr = RHSExp;
+    ResultType = Context.DependentTy;
+  } else if (const PointerType *PTy = LHSTy->getAsPointerType()) {
     BaseExpr = LHSExp;
     IndexExpr = RHSExp;
     // FIXME: need to deal with const...
@@ -1526,7 +1540,7 @@
       diag::err_typecheck_subscript_value) << RHSExp->getSourceRange());
   }
   // C99 6.5.2.1p1
-  if (!IndexExpr->getType()->isIntegerType())
+  if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent())
     return ExprError(Diag(IndexExpr->getLocStart(),
       diag::err_typecheck_subscript) << IndexExpr->getSourceRange());
 
@@ -1534,7 +1548,7 @@
   // the following check catches trying to index a pointer to a function (e.g.
   // void (*)(int)) and pointers to incomplete types.  Functions are not
   // objects in C99.
-  if (!ResultType->isObjectType())
+  if (!ResultType->isObjectType() && !ResultType->isDependentType())
     return ExprError(Diag(BaseExpr->getLocStart(),
                 diag::err_typecheck_subscript_not_object)
       << BaseExpr->getType() << BaseExpr->getSourceRange());
@@ -2306,8 +2320,8 @@
                                             LParenLoc, RParenLoc));
 }
 
-/// Note that lex is not null here, even if this is the gnu "x ?: y" extension.
-/// In that case, lex = cond.
+/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
+/// In that case, lhs = cond.
 /// C99 6.5.15
 QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
                                         SourceLocation QuestionLoc) {
@@ -3442,6 +3456,9 @@
 /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
 QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
                                               bool isInc) {
+  if (Op->isTypeDependent())
+    return Context.DependentTy;
+
   QualType ResType = Op->getType();
   assert(!ResType.isNull() && "no type for increment/decrement expression");
 
@@ -3669,6 +3686,9 @@
 }
 
 QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) {
+  if (Op->isTypeDependent())
+    return Context.DependentTy;
+
   UsualUnaryConversions(Op);
   QualType Ty = Op->getType();
 
@@ -4120,6 +4140,8 @@
   case UnaryOperator::Minus:
     UsualUnaryConversions(Input);
     resultType = Input->getType();
+    if (resultType->isDependentType())
+      break;
     if (resultType->isArithmeticType()) // C99 6.5.3.3p1
       break;
     else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7
@@ -4135,6 +4157,8 @@
   case UnaryOperator::Not: // bitwise complement
     UsualUnaryConversions(Input);
     resultType = Input->getType();
+    if (resultType->isDependentType())
+      break;
     // C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
     if (resultType->isComplexType() || resultType->isComplexIntegerType())
       // C99 does not support '~' for complex conjugation.
@@ -4148,6 +4172,8 @@
     // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
     DefaultFunctionArrayConversion(Input);
     resultType = Input->getType();
+    if (resultType->isDependentType())
+      break;
     if (!resultType->isScalarType()) // C99 6.5.3.3p1
       return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
         << resultType << Input->getSourceRange());
@@ -4231,10 +4257,12 @@
   QualType ArgTy = QualType::getFromOpaquePtr(argty);
   assert(!ArgTy.isNull() && "Missing type argument!");
 
+  bool Dependent = ArgTy->isDependentType();
+
   // We must have at least one component that refers to the type, and the first
   // one is known to be a field designator.  Verify that the ArgTy represents
   // a struct/union/class.
-  if (!ArgTy->isRecordType())
+  if (!Dependent && !ArgTy->isRecordType())
     return Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy;
 
   // Otherwise, create a compound literal expression as the base, and
@@ -4251,51 +4279,57 @@
     Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
       << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
 
-  for (unsigned i = 0; i != NumComponents; ++i) {
-    const OffsetOfComponent &OC = CompPtr[i];
-    if (OC.isBrackets) {
-      // Offset of an array sub-field.  TODO: Should we allow vector elements?
-      const ArrayType *AT = Context.getAsArrayType(Res->getType());
-      if (!AT) {
-        Res->Destroy(Context);
-        return Diag(OC.LocEnd, diag::err_offsetof_array_type) << Res->getType();
+  if (!Dependent) {
+    // FIXME: Dependent case loses a lot of information here. And probably
+    // leaks like a sieve.
+    for (unsigned i = 0; i != NumComponents; ++i) {
+      const OffsetOfComponent &OC = CompPtr[i];
+      if (OC.isBrackets) {
+        // Offset of an array sub-field.  TODO: Should we allow vector elements?
+        const ArrayType *AT = Context.getAsArrayType(Res->getType());
+        if (!AT) {
+          Res->Destroy(Context);
+          return Diag(OC.LocEnd, diag::err_offsetof_array_type)
+            << Res->getType();
+        }
+
+        // FIXME: C++: Verify that operator[] isn't overloaded.
+
+        // C99 6.5.2.1p1
+        Expr *Idx = static_cast<Expr*>(OC.U.E);
+        if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
+          return Diag(Idx->getLocStart(), diag::err_typecheck_subscript)
+            << Idx->getSourceRange();
+
+        Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
+                                               OC.LocEnd);
+        continue;
       }
 
-      // FIXME: C++: Verify that operator[] isn't overloaded.
+      const RecordType *RC = Res->getType()->getAsRecordType();
+      if (!RC) {
+        Res->Destroy(Context);
+        return Diag(OC.LocEnd, diag::err_offsetof_record_type)
+          << Res->getType();
+      }
 
-      // C99 6.5.2.1p1
-      Expr *Idx = static_cast<Expr*>(OC.U.E);
-      if (!Idx->getType()->isIntegerType())
-        return Diag(Idx->getLocStart(), diag::err_typecheck_subscript)
-          << Idx->getSourceRange();
-
-      Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
-                                             OC.LocEnd);
-      continue;
-    }
-
-    const RecordType *RC = Res->getType()->getAsRecordType();
-    if (!RC) {
-      Res->Destroy(Context);
-      return Diag(OC.LocEnd, diag::err_offsetof_record_type) << Res->getType();
-    }
-
-    // Get the decl corresponding to this.
-    RecordDecl *RD = RC->getDecl();
-    FieldDecl *MemberDecl
-      = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
-                                                        LookupMemberName)
-                                      .getAsDecl());
-    if (!MemberDecl)
-      return Diag(BuiltinLoc, diag::err_typecheck_no_member)
-       << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd);
-
-    // FIXME: C++: Verify that MemberDecl isn't a static field.
-    // FIXME: Verify that MemberDecl isn't a bitfield.
-    // MemberDecl->getType() doesn't get the right qualifiers, but it doesn't
-    // matter here.
-    Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
+      // Get the decl corresponding to this.
+      RecordDecl *RD = RC->getDecl();
+      FieldDecl *MemberDecl
+        = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo,
+                                                          LookupMemberName)
+                                        .getAsDecl());
+      if (!MemberDecl)
+        return Diag(BuiltinLoc, diag::err_typecheck_no_member)
+         << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd);
+
+      // FIXME: C++: Verify that MemberDecl isn't a static field.
+      // FIXME: Verify that MemberDecl isn't a bitfield.
+      // MemberDecl->getType() doesn't get the right qualifiers, but it doesn't
+      // matter here.
+      Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
                                    MemberDecl->getType().getNonReferenceType());
+    }
   }
 
   return new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
@@ -4324,16 +4358,21 @@
 
   assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
 
-  // The conditional expression is required to be a constant expression.
-  llvm::APSInt condEval(32);
-  SourceLocation ExpLoc;
-  if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
-    return Diag(ExpLoc, diag::err_typecheck_choose_expr_requires_constant)
-      << CondExpr->getSourceRange();
-
-  // If the condition is > zero, then the AST type is the same as the LSHExpr.
-  QualType resType = condEval.getZExtValue() ? LHSExpr->getType() :
-                                               RHSExpr->getType();
+  QualType resType;
+  if (CondExpr->isValueDependent()) {
+    resType = Context.DependentTy;
+  } else {
+    // The conditional expression is required to be a constant expression.
+    llvm::APSInt condEval(32);
+    SourceLocation ExpLoc;
+    if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
+      return Diag(ExpLoc, diag::err_typecheck_choose_expr_requires_constant)
+        << CondExpr->getSourceRange();
+
+    // If the condition is > zero, then the AST type is the same as the LSHExpr.
+    resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType();
+  }
+
   return new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
                                   resType, RPLoc);
 }

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=65529&r1=65528&r2=65529&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb 26 08:39:58 2009
@@ -134,6 +134,8 @@
                                                TyBeginLoc, Exprs[0], RParenLoc);
   }
 
+  // FIXME: What AST node to create when the type is dependent?
+
   if (const RecordType *RT = Ty->getAsRecordType()) {
     CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
     
@@ -220,14 +222,16 @@
   if (CheckAllocatedType(AllocType, D))
     return true;
 
-  QualType ResultType = Context.getPointerType(AllocType);
+  QualType ResultType = AllocType->isDependentType()
+                          ? Context.DependentTy
+                          : Context.getPointerType(AllocType);
 
   // That every array dimension except the first is constant was already
   // checked by the type check above.
 
   // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
   //   or enumeration type with a non-negative value."
-  if (ArraySize) {
+  if (ArraySize && !ArraySize->isTypeDependent()) {
     QualType SizeType = ArraySize->getType();
     if (!SizeType->isIntegralType() && !SizeType->isEnumeralType())
       return Diag(ArraySize->getSourceRange().getBegin(),
@@ -236,20 +240,24 @@
     // Let's see if this is a constant < 0. If so, we reject it out of hand.
     // We don't care about special rules, so we tell the machinery it's not
     // evaluated - it gives us a result in more cases.
-    llvm::APSInt Value;
-    if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
-      if (Value < llvm::APSInt(
-                      llvm::APInt::getNullValue(Value.getBitWidth()), false))
-        return Diag(ArraySize->getSourceRange().getBegin(),
-                    diag::err_typecheck_negative_array_size)
-          << ArraySize->getSourceRange();
+    if (!ArraySize->isValueDependent()) {
+      llvm::APSInt Value;
+      if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
+        if (Value < llvm::APSInt(
+                        llvm::APInt::getNullValue(Value.getBitWidth()), false))
+          return Diag(ArraySize->getSourceRange().getBegin(),
+                      diag::err_typecheck_negative_array_size)
+            << ArraySize->getSourceRange();
+      }
     }
   }
 
   FunctionDecl *OperatorNew = 0;
   FunctionDecl *OperatorDelete = 0;
   Expr **PlaceArgs = (Expr**)PlacementArgs;
-  if (FindAllocationFunctions(StartLoc,
+  if (!AllocType->isDependentType() &&
+      !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) &&
+      FindAllocationFunctions(StartLoc,
                               SourceRange(PlacementLParen, PlacementRParen),
                               UseGlobal, AllocType, ArraySize, PlaceArgs,
                               NumPlaceArgs, OperatorNew, OperatorDelete))
@@ -275,8 +283,11 @@
   // 2) Otherwise, the object is direct-initialized.
   CXXConstructorDecl *Constructor = 0;
   Expr **ConsArgs = (Expr**)ConstructorArgs;
+  if (AllocType->isDependentType()) {
+    // Skip all the checks.
+  }
   // FIXME: Should check for primitive/aggregate here, not record.
-  if (const RecordType *RT = AllocType->getAsRecordType()) {
+  else if (const RecordType *RT = AllocType->getAsRecordType()) {
     // FIXME: This is incorrect for when there is an empty initializer and
     // no user-defined constructor. Must zero-initialize, not default-construct.
     Constructor = PerformInitializationByConstructor(
@@ -570,31 +581,33 @@
   // DR599 amends "pointer type" to "pointer to object type" in both cases.
 
   Expr *Ex = (Expr *)Operand;
-  QualType Type = Ex->getType();
+  if (!Ex->isTypeDependent()) {
+    QualType Type = Ex->getType();
 
-  if (Type->isRecordType()) {
-    // FIXME: Find that one conversion function and amend the type.
-  }
+    if (Type->isRecordType()) {
+      // FIXME: Find that one conversion function and amend the type.
+    }
 
-  if (!Type->isPointerType()) {
-    Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange();
-    return true;
-  }
+    if (!Type->isPointerType()) {
+      Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange();
+      return true;
+    }
 
-  QualType Pointee = Type->getAsPointerType()->getPointeeType();
-  if (!Pointee->isVoidType() && 
-      DiagnoseIncompleteType(StartLoc, Pointee, diag::warn_delete_incomplete,
-                             Ex->getSourceRange()))
-    return true;
-  else if (!Pointee->isObjectType()) {
-    Diag(StartLoc, diag::err_delete_operand)
-      << Type << Ex->getSourceRange();
-    return true;
-  }
+    QualType Pointee = Type->getAsPointerType()->getPointeeType();
+    if (!Pointee->isVoidType() && 
+        DiagnoseIncompleteType(StartLoc, Pointee, diag::warn_delete_incomplete,
+                               Ex->getSourceRange()))
+      return true;
+    else if (!Pointee->isObjectType()) {
+      Diag(StartLoc, diag::err_delete_operand)
+        << Type << Ex->getSourceRange();
+      return true;
+    }
 
-  // FIXME: Look up the correct operator delete overload and pass a pointer
-  // along.
-  // FIXME: Check access and ambiguity of operator delete and destructor.
+    // FIXME: Look up the correct operator delete overload and pass a pointer
+    // along.
+    // FIXME: Check access and ambiguity of operator delete and destructor.
+  }
 
   return new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, 0,
                                      Ex, StartLoc);

Added: cfe/trunk/test/SemaTemplate/fun-template-def.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/fun-template-def.cpp?rev=65529&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/fun-template-def.cpp (added)
+++ cfe/trunk/test/SemaTemplate/fun-template-def.cpp Thu Feb 26 08:39:58 2009
@@ -0,0 +1,43 @@
+// RUN: clang -fsyntax-only -verify %s
+
+// Tests that dependent expressions are always allowed, whereas non-dependent
+// are checked as usual.
+
+#include <stddef.h>
+
+// Fake typeid, lacking a typeinfo header.
+namespace std { class type_info {}; }
+
+struct dummy {};
+
+template <typename T, typename U>
+T f(T t1, U u1, int i1)
+{
+  T t2 = i1;
+  t2 = i1 + u1;
+  ++u1;
+  u1++;
+  int i2 = u1;
+
+  i1 = t1[u1];
+  i1 *= t1;
+
+  i1(u1, t1); // error
+  u1(i1, t1);
+
+  U u2 = (T)i1;
+  static_cast<void>(static_cast<U>(reinterpret_cast<T>(
+    dynamic_cast<U>(const_cast<T>(i1)))));
+
+  new U(i1, t1);
+  new int(t1, u1); // expected-error {{initializer of a builtin type can only take one argument}}
+  new (t1, u1) int;
+  delete t1;
+
+  dummy d1 = sizeof(t1); // expected-error {{cannot initialize 'd1'}}
+  dummy d2 = offsetof(T, foo); // expected-error {{cannot initialize 'd2'}}
+  dummy d3 = __alignof(u1); // expected-error {{cannot initialize 'd3'}}
+  i1 = typeid(t1); // expected-error {{incompatible type assigning}}
+
+  return u1;
+}





More information about the cfe-commits mailing list