From 2850784bda09416fc7e9d57f5baa36c9351c757c Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Thu, 26 Feb 2009 14:39:58 +0000 Subject: [PATCH] Make more AST nodes and semantic checkers dependent-expression-aware. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65529 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 13 ++- include/clang/AST/ExprCXX.h | 23 +++- lib/AST/ExprCXX.cpp | 3 +- lib/Sema/SemaExpr.cpp | 155 ++++++++++++++++--------- lib/Sema/SemaExprCXX.cpp | 81 +++++++------ test/SemaTemplate/fun-template-def.cpp | 43 +++++++ 6 files changed, 216 insertions(+), 102 deletions(-) create mode 100644 test/SemaTemplate/fun-template-def.cpp diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 9e19940506..baf8c13279 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -680,8 +680,12 @@ public: 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(argument)->isTypeDependent())), + isSizeof(issizeof), isType(istype), OpLoc(op), RParenLoc(rp) { if (isType) Argument.Ty = argument; else @@ -742,7 +746,10 @@ class ArraySubscriptExpr : public Expr { 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; } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 3d33ee4a14..675732aa07 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -227,12 +227,18 @@ private: 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(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(op); + Operand.Ex = static_cast(op); } bool isTypeOperand() const { return isTypeOp; } @@ -277,7 +283,11 @@ class CXXThisExpr : public Expr { 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 @@ public: // 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(Op); } Expr *getSubExpr() { return cast_or_null(Op); } @@ -578,7 +588,8 @@ class CXXNewExpr : public Expr { 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 @@ class CXXDeleteExpr : public Expr { 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) { } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index e3d78eebec..d60ef39070 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -95,7 +95,8 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, 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), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 98d6b12b9c..1f8cb80cd3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1159,10 +1159,13 @@ Action::OwningExprResult Sema::ActOnParenExpr(SourceLocation L, /// 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(exprType)) { // alignof(function) is allowed. @@ -1186,11 +1189,15 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &ExprRange) { E = E->IgnoreParens(); - + // alignof decl is always ok. if (isa(E)) return false; - + + // Cannot know anything else if the expression is dependent. + if (E->isTypeDependent()) + return false; + if (MemberExpr *ME = dyn_cast(E)) { if (FieldDecl *FD = dyn_cast(ME->getMemberDecl())) { if (FD->isBitField()) { @@ -1252,6 +1259,9 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, } 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, // 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 @@ Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, 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 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { /// 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::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { } QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { + if (Op->isTypeDependent()) + return Context.DependentTy; + UsualUnaryConversions(Op); QualType Ty = Op->getType(); @@ -4120,6 +4140,8 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, 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 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, 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 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, // 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 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, 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 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, 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(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(OC.U.E); - if (!Idx->getType()->isIntegerType()) - return Diag(Idx->getLocStart(), diag::err_typecheck_subscript) - << Idx->getSourceRange(); + // Get the decl corresponding to this. + RecordDecl *RD = RC->getDecl(); + FieldDecl *MemberDecl + = dyn_cast_or_null(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); - 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(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, + // 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 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond, 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(); + 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(); + } - // If the condition is > zero, then the AST type is the same as the LSHExpr. - QualType resType = condEval.getZExtValue() ? LHSExpr->getType() : - RHSExpr->getType(); return new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c8671bc2e3..6023469193 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -134,6 +134,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, TyBeginLoc, Exprs[0], RParenLoc); } + // FIXME: What AST node to create when the type is dependent? + if (const RecordType *RT = Ty->getAsRecordType()) { CXXRecordDecl *Record = cast(RT->getDecl()); @@ -220,14 +222,16 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, 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 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, // 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 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, // 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,32 +581,34 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // 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; + } + + 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. } - 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; - } - - // 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); } diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp new file mode 100644 index 0000000000..e9871bb5c9 --- /dev/null +++ b/test/SemaTemplate/fun-template-def.cpp @@ -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 + +// Fake typeid, lacking a typeinfo header. +namespace std { class type_info {}; } + +struct dummy {}; + +template +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(static_cast(reinterpret_cast( + dynamic_cast(const_cast(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; +}