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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 98d6b12..1f8cb80 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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();
+ // 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 @@
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.
- QualType resType = condEval.getZExtValue() ? LHSExpr->getType() :
- RHSExpr->getType();
+ // 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);
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index c8671bc..6023469 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -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,32 +581,34 @@
// 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);
}