зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
b558422a49
Коммит
2850784bda
|
@ -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<Expr*>(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;
|
||||
}
|
||||
|
|
|
@ -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<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 @@ 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<Expr>(Op); }
|
||||
Expr *getSubExpr() { return cast_or_null<Expr>(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) { }
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<FunctionType>(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<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 @@ 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<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();
|
||||
// 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);
|
||||
|
||||
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,
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -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<CXXRecordDecl>(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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
Загрузка…
Ссылка в новой задаче