Introduce basic support for dependent types, type-dependent
expressions, and value-dependent expressions. This permits us to parse
some template definitions.
This is not a complete solution; we're missing type- and
value-dependent computations for most of the expression types, and
we're missing checks for dependent types and type-dependent
expressions throughout Sema.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60615 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c893d27..e581b10 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -870,9 +870,8 @@
if (PrevDecl && isTemplateParameterDecl(PrevDecl)) {
// Maybe we will complain about the shadowed template parameter.
- InvalidDecl
- = InvalidDecl || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
- PrevDecl);
+ InvalidDecl = InvalidDecl
+ || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
// Just pretend that we didn't see the previous declaration.
PrevDecl = 0;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index ec86b9f..e4beb74 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -490,7 +490,52 @@
}
// If this reference is not in a block or if the referenced variable is
// within the block, create a normal DeclRefExpr.
- return new DeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc);
+
+ // C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ bool TypeDependent = false;
+
+ // - an identifier that was declared with a dependent type,
+ if (VD->getType()->isDependentType())
+ TypeDependent = true;
+ // - FIXME: a template-id that is dependent,
+ // - a conversion-function-id that specifies a dependent type,
+ else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType())
+ TypeDependent = true;
+ // - a nested-name-specifier that contains a class-name that
+ // names a dependent type.
+ else if (SS && !SS->isEmpty()) {
+ for (DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
+ DC; DC = DC->getParent()) {
+ // FIXME: could stop early at namespace scope.
+ if (DC->isCXXRecord()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ if (Context.getTypeDeclType(Record)->isDependentType()) {
+ TypeDependent = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // C++ [temp.dep.constexpr]p2:
+ //
+ // An identifier is value-dependent if it is:
+ bool ValueDependent = false;
+
+ // - a name declared with a dependent type,
+ if (TypeDependent)
+ ValueDependent = true;
+ // - the name of a non-type template parameter,
+ else if (isa<NonTypeTemplateParmDecl>(VD))
+ ValueDependent = true;
+ // - a constant with integral or enumeration type and is
+ // initialized with an expression that is value-dependent
+ // (FIXME!).
+
+ return new DeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
+ TypeDependent, ValueDependent);
}
Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -1279,6 +1324,11 @@
FunctionDecl *FDecl = NULL;
OverloadedFunctionDecl *Ovl = NULL;
+ // FIXME: Will need to cache the results of name lookup (including
+ // ADL) in Fn.
+ if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(Args, NumArgs))
+ return new CallExpr(Fn, Args, NumArgs, Context.DependentTy, RParenLoc);
+
// If we're directly calling a function or a set of overloaded
// functions, get the appropriate declaration.
{
@@ -1318,6 +1368,7 @@
// of arguments and function on error.
llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgs,
Context.BoolTy, RParenLoc));
+
const FunctionType *FuncT;
if (!Fn->getType()->isBlockPointerType()) {
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
@@ -1470,6 +1521,8 @@
// type needs to be scalar.
if (castType->isVoidType()) {
// Cast to void allows any expr type.
+ } else if (castType->isDependentType() || castExpr->isTypeDependent()) {
+ // We can't check any more until template instantiation time.
} else if (!castType->isScalarType() && !castType->isVectorType()) {
// GCC struct/union extension: allow cast to self.
if (Context.getCanonicalType(castType) !=
@@ -1541,13 +1594,17 @@
QualType rexT = rex->getType();
// first, check the condition.
- if (!condT->isScalarType()) { // C99 6.5.15p2
- Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) << condT;
- return QualType();
+ if (!cond->isTypeDependent()) {
+ if (!condT->isScalarType()) { // C99 6.5.15p2
+ Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) << condT;
+ return QualType();
+ }
}
// Now check the two expressions.
-
+ if ((lex && lex->isTypeDependent()) || (rex && rex->isTypeDependent()))
+ return Context.DependentTy;
+
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
if (lexT->isArithmeticType() && rexT->isArithmeticType()) {
@@ -2959,6 +3016,17 @@
assert((lhs != 0) && "ActOnBinOp(): missing left expression");
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
+ // If either expression is type-dependent, just build the AST.
+ // FIXME: We'll need to perform some caching of the result of name
+ // lookup for operator+.
+ if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
+ if (Opc > BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign)
+ return new CompoundAssignOperator(lhs, rhs, Opc, Context.DependentTy,
+ Context.DependentTy, TokLoc);
+ else
+ return new BinaryOperator(lhs, rhs, Opc, Context.DependentTy, TokLoc);
+ }
+
if (getLangOptions().CPlusPlus &&
(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() ||
rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 1e9b945..c4cab33 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -163,9 +163,9 @@
//
if (Ty->isArrayType())
return Diag(TyBeginLoc, diag::err_value_init_for_array_type) << FullRange;
- if (Ty->isIncompleteType() && !Ty->isVoidType())
+ if (!Ty->isDependentType() && Ty->isIncompleteType() && !Ty->isVoidType())
return Diag(TyBeginLoc, diag::err_invalid_incomplete_type_use)
- << Ty << FullRange;
+ << Ty << FullRange;
return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc);
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 0159f5f..21f897f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -782,21 +782,23 @@
return new ReturnStmt(ReturnLoc, (Expr*)0);
}
- // we have a non-void function with an expression, continue checking
- QualType RetValType = RetValExp->getType();
-
- // C99 6.8.6.4p3(136): The return statement is not an assignment. The
- // overlap restriction of subclause 6.5.16.1 does not apply to the case of
- // function return.
-
- // In C++ the return statement is handled via a copy initialization.
- // the C version of which boils down to
- // CheckSingleAssignmentConstraints.
- if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
- return true;
+ if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
+ // we have a non-void function with an expression, continue checking
+ QualType RetValType = RetValExp->getType();
+
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // function return.
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to
+ // CheckSingleAssignmentConstraints.
+ if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
+ return true;
- if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
-
+ if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ }
+
return new ReturnStmt(ReturnLoc, (Expr*)RetValExp);
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 749d181..092c9d2 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -12,6 +12,7 @@
//+//===----------------------------------------------------------------------===/
#include "Sema.h"
+#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4487c1e..2423e12 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -391,6 +391,8 @@
llvm::APSInt ConstVal(32);
if (!ArraySize) {
T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals);
+ } else if (ArraySize->isValueDependent()) {
+ T = Context.getDependentSizedArrayType(T, ArraySize, ASM, ATI.TypeQuals);
} else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
!T->isConstantSizeType()) {
// Per C99, a variable array is an array with either a non-constant
@@ -416,7 +418,8 @@
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOptions().C99 &&
(ASM != ArrayType::Normal ||
- (ArraySize && !ArraySize->isIntegerConstantExpr(Context))))
+ (ArraySize && !ArraySize->isValueDependent() &&
+ !ArraySize->isIntegerConstantExpr(Context))))
Diag(D.getIdentifierLoc(), diag::ext_vla);
break;
}