Implement template instantiation for several more kinds of expressions:
- C++ function casts, e.g., T(foo) - sizeof(), alignof() More importantly, this allows us to verify that we're performing overload resolution during template instantiation, with argument-dependent lookup and the "cached" results of name lookup from the template definition. llvm-svn: 66947
This commit is contained in:
parent
5b86bf527e
commit
0950e41b73
|
@ -2553,8 +2553,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
FT->getResultType(), SourceLocation());
|
||||
|
||||
// Build sizeof(returnType)
|
||||
SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, true,
|
||||
returnType.getAsOpaquePtr(),
|
||||
SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
|
||||
returnType,
|
||||
Context->getSizeType(),
|
||||
SourceLocation(), SourceLocation());
|
||||
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
|
||||
|
|
|
@ -692,20 +692,26 @@ class SizeOfAlignOfExpr : public Expr {
|
|||
} Argument;
|
||||
SourceLocation OpLoc, RParenLoc;
|
||||
public:
|
||||
SizeOfAlignOfExpr(bool issizeof, bool istype, void *argument,
|
||||
SizeOfAlignOfExpr(bool issizeof, QualType T,
|
||||
QualType resultType, SourceLocation op,
|
||||
SourceLocation rp) :
|
||||
Expr(SizeOfAlignOfExprClass, resultType,
|
||||
false, // Never type-dependent.
|
||||
false, // Never type-dependent (C++ [temp.dep.expr]p3).
|
||||
// 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
|
||||
// argument was an Expr*, so cast it back to that to be safe
|
||||
Argument.Ex = static_cast<Expr*>(argument);
|
||||
T->isDependentType()),
|
||||
isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) {
|
||||
Argument.Ty = T.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
SizeOfAlignOfExpr(bool issizeof, Expr *E,
|
||||
QualType resultType, SourceLocation op,
|
||||
SourceLocation rp) :
|
||||
Expr(SizeOfAlignOfExprClass, resultType,
|
||||
false, // Never type-dependent (C++ [temp.dep.expr]p3).
|
||||
// Value-dependent if the argument is type-dependent.
|
||||
E->isTypeDependent()),
|
||||
isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) {
|
||||
Argument.Ex = E;
|
||||
}
|
||||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
|
|
@ -467,6 +467,8 @@ public:
|
|||
const_arg_iterator arg_begin() const { return Args; }
|
||||
const_arg_iterator arg_end() const { return Args + NumArgs; }
|
||||
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(TyBeginLoc, RParenLoc);
|
||||
}
|
||||
|
|
|
@ -216,7 +216,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
|
|||
Expr **Args,
|
||||
unsigned NumArgs,
|
||||
SourceLocation rParenLoc)
|
||||
: Expr(CXXTemporaryObjectExprClass, writtenTy),
|
||||
: Expr(CXXTemporaryObjectExprClass, writtenTy,
|
||||
writtenTy->isDependentType(),
|
||||
(writtenTy->isDependentType() ||
|
||||
CallExpr::hasAnyValueDependentArguments(Args, NumArgs))),
|
||||
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc),
|
||||
Constructor(Cons), Args(0), NumArgs(NumArgs) {
|
||||
if (NumArgs > 0) {
|
||||
|
|
|
@ -833,8 +833,13 @@ SizeOfAlignOfExpr::CreateImpl(Deserializer& D, ASTContext& C) {
|
|||
SourceLocation OpLoc = SourceLocation::ReadVal(D);
|
||||
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
|
||||
|
||||
return new SizeOfAlignOfExpr(isSizeof, isType, Argument, Res,
|
||||
OpLoc, RParenLoc);
|
||||
if (isType)
|
||||
return new (C) SizeOfAlignOfExpr(isSizeof,
|
||||
QualType::getFromOpaquePtr(Argument),
|
||||
Res, OpLoc, RParenLoc);
|
||||
|
||||
return new (C) SizeOfAlignOfExpr(isSizeof, (Expr *)Argument,
|
||||
Res, OpLoc, RParenLoc);
|
||||
}
|
||||
|
||||
void StmtExpr::EmitImpl(Serializer& S) const {
|
||||
|
|
|
@ -967,9 +967,12 @@ ClassTemplateSpecializationType(TemplateDecl *T, const TemplateArgument *Args,
|
|||
}
|
||||
|
||||
void ClassTemplateSpecializationType::Destroy(ASTContext& C) {
|
||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
||||
if (Expr *E = getArg(Arg).getAsExpr())
|
||||
E->Destroy(C);
|
||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
|
||||
// FIXME: Not all expressions get cloned, so we can't yet perform
|
||||
// this destruction.
|
||||
// if (Expr *E = getArg(Arg).getAsExpr())
|
||||
// E->Destroy(C);
|
||||
}
|
||||
}
|
||||
|
||||
ClassTemplateSpecializationType::iterator
|
||||
|
|
|
@ -1188,6 +1188,11 @@ public:
|
|||
ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
|
||||
void *TyOrEx, const SourceRange &ArgRange);
|
||||
|
||||
OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
|
||||
bool isSizeOf, SourceRange R);
|
||||
OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
|
||||
bool isSizeOf, SourceRange R);
|
||||
|
||||
bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R);
|
||||
bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
|
||||
const SourceRange &R, bool isSizeof);
|
||||
|
|
|
@ -1220,6 +1220,50 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
|
|||
return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
|
||||
}
|
||||
|
||||
/// \brief Build a sizeof or alignof expression given a type operand.
|
||||
Action::OwningExprResult
|
||||
Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc,
|
||||
bool isSizeOf, SourceRange R) {
|
||||
if (T.isNull())
|
||||
return ExprError();
|
||||
|
||||
if (!T->isDependentType() &&
|
||||
CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
|
||||
return ExprError();
|
||||
|
||||
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
|
||||
return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, T,
|
||||
Context.getSizeType(), OpLoc,
|
||||
R.getEnd()));
|
||||
}
|
||||
|
||||
/// \brief Build a sizeof or alignof expression given an expression
|
||||
/// operand.
|
||||
Action::OwningExprResult
|
||||
Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc,
|
||||
bool isSizeOf, SourceRange R) {
|
||||
// Verify that the operand is valid.
|
||||
bool isInvalid = false;
|
||||
if (E->isTypeDependent()) {
|
||||
// Delay type-checking for type-dependent expressions.
|
||||
} else if (!isSizeOf) {
|
||||
isInvalid = CheckAlignOfExpr(E, OpLoc, R);
|
||||
} else if (E->isBitField()) { // C99 6.5.3.4p1.
|
||||
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
|
||||
isInvalid = true;
|
||||
} else {
|
||||
isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true);
|
||||
}
|
||||
|
||||
if (isInvalid)
|
||||
return ExprError();
|
||||
|
||||
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
|
||||
return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E,
|
||||
Context.getSizeType(), OpLoc,
|
||||
R.getEnd()));
|
||||
}
|
||||
|
||||
/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and
|
||||
/// the same for @c alignof and @c __alignof
|
||||
/// Note that the ArgRange is invalid if isType is false.
|
||||
|
@ -1229,42 +1273,20 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
|
|||
// If error parsing type, ignore.
|
||||
if (TyOrEx == 0) return ExprError();
|
||||
|
||||
QualType ArgTy;
|
||||
SourceRange Range;
|
||||
if (isType) {
|
||||
ArgTy = QualType::getFromOpaquePtr(TyOrEx);
|
||||
Range = ArgRange;
|
||||
QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx);
|
||||
return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange);
|
||||
}
|
||||
|
||||
// Verify that the operand is valid.
|
||||
if (CheckSizeOfAlignOfOperand(ArgTy, OpLoc, Range, isSizeof))
|
||||
return ExprError();
|
||||
} else {
|
||||
// Get the end location.
|
||||
Expr *ArgEx = (Expr *)TyOrEx;
|
||||
Range = ArgEx->getSourceRange();
|
||||
ArgTy = ArgEx->getType();
|
||||
Action::OwningExprResult Result
|
||||
= CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange());
|
||||
|
||||
// Verify that the operand is valid.
|
||||
bool isInvalid;
|
||||
if (!isSizeof) {
|
||||
isInvalid = CheckAlignOfExpr(ArgEx, OpLoc, Range);
|
||||
} else if (ArgEx->isBitField()) { // C99 6.5.3.4p1.
|
||||
Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
|
||||
isInvalid = true;
|
||||
} else {
|
||||
isInvalid = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, Range, true);
|
||||
}
|
||||
|
||||
if (isInvalid) {
|
||||
if (Result.isInvalid())
|
||||
DeleteExpr(ArgEx);
|
||||
return ExprError();
|
||||
}
|
||||
}
|
||||
|
||||
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
|
||||
return Owned(new (Context) SizeOfAlignOfExpr(isSizeof, isType, TyOrEx,
|
||||
Context.getSizeType(), OpLoc,
|
||||
Range.getEnd()));
|
||||
return move(Result);
|
||||
}
|
||||
|
||||
QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
|
||||
|
|
|
@ -122,6 +122,13 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
|
|||
SourceLocation TyBeginLoc = TypeRange.getBegin();
|
||||
SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc);
|
||||
|
||||
if (Ty->isDependentType() ||
|
||||
CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
|
||||
return new (Context) CXXTemporaryObjectExpr(0, Ty, TyBeginLoc,
|
||||
Exprs, NumExprs, RParenLoc);
|
||||
}
|
||||
|
||||
|
||||
// C++ [expr.type.conv]p1:
|
||||
// If the expression list is a single expression, the type conversion
|
||||
// expression is equivalent (in definedness, and if defined in meaning) to the
|
||||
|
@ -134,8 +141,6 @@ 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());
|
||||
|
||||
|
|
|
@ -1392,6 +1392,9 @@ static bool
|
|||
IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
|
||||
QualType T1, QualType T2,
|
||||
ASTContext &Context) {
|
||||
if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
|
||||
return true;
|
||||
|
||||
if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -1276,6 +1276,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
if (const EnumType *Enum = IntegerType->getAsEnumType())
|
||||
IntegerType = Enum->getDecl()->getIntegerType();
|
||||
|
||||
if (Arg->isValueDependent()) {
|
||||
// The argument is value-dependent. Create a new
|
||||
// TemplateArgument with the converted expression.
|
||||
Converted->push_back(TemplateArgument(Arg));
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::APInt CanonicalArg(Context.getTypeSize(IntegerType), 0,
|
||||
IntegerType->isSignedIntegerType());
|
||||
CanonicalArg = Value;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Lex/Preprocessor.h" // for the identifier table
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
|
@ -441,7 +442,12 @@ InstantiateClassTemplateSpecializationType(
|
|||
break;
|
||||
|
||||
case TemplateArgument::Expression:
|
||||
assert(false && "Cannot instantiate expressions yet");
|
||||
Sema::OwningExprResult E
|
||||
= SemaRef.InstantiateExpr(Arg->getAsExpr(), TemplateArgs,
|
||||
NumTemplateArgs);
|
||||
if (E.isInvalid())
|
||||
return QualType();
|
||||
InstantiatedTemplateArgs.push_back((Expr *)E.release());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -564,6 +570,8 @@ namespace {
|
|||
unsigned NumTemplateArgs;
|
||||
|
||||
public:
|
||||
typedef Sema::OwningExprResult OwningExprResult;
|
||||
|
||||
TemplateExprInstantiator(Sema &SemaRef,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs)
|
||||
|
@ -573,11 +581,13 @@ namespace {
|
|||
// FIXME: Once we get closer to completion, replace these
|
||||
// manually-written declarations with automatically-generated ones
|
||||
// from clang/AST/StmtNodes.def.
|
||||
Sema::OwningExprResult VisitIntegerLiteral(IntegerLiteral *E);
|
||||
Sema::OwningExprResult VisitDeclRefExpr(DeclRefExpr *E);
|
||||
Sema::OwningExprResult VisitParenExpr(ParenExpr *E);
|
||||
Sema::OwningExprResult VisitBinaryOperator(BinaryOperator *E);
|
||||
Sema::OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
|
||||
OwningExprResult VisitIntegerLiteral(IntegerLiteral *E);
|
||||
OwningExprResult VisitDeclRefExpr(DeclRefExpr *E);
|
||||
OwningExprResult VisitParenExpr(ParenExpr *E);
|
||||
OwningExprResult VisitBinaryOperator(BinaryOperator *E);
|
||||
OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
|
||||
OwningExprResult VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
|
||||
OwningExprResult VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
|
||||
|
||||
// Base case. I'm supposed to ignore this.
|
||||
Sema::OwningExprResult VisitStmt(Stmt *) {
|
||||
|
@ -692,6 +702,9 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
|
|||
DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
|
||||
OverloadedFunctionDecl *Overloads
|
||||
= cast<OverloadedFunctionDecl>(DRE->getDecl());
|
||||
|
||||
// FIXME: Do we have to check
|
||||
// IsAcceptableNonMemberOperatorCandidate for each of these?
|
||||
for (OverloadedFunctionDecl::function_iterator
|
||||
F = Overloads->function_begin(),
|
||||
FEnd = Overloads->function_end();
|
||||
|
@ -716,6 +729,90 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
|
|||
return move(Result);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
|
||||
bool isSizeOf = E->isSizeOf();
|
||||
|
||||
if (E->isArgumentType()) {
|
||||
QualType T = E->getArgumentType();
|
||||
if (T->isDependentType()) {
|
||||
T = SemaRef.InstantiateType(T, TemplateArgs, NumTemplateArgs,
|
||||
/*FIXME*/E->getOperatorLoc(),
|
||||
&SemaRef.PP.getIdentifierTable().get("sizeof"));
|
||||
if (T.isNull())
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
return SemaRef.CreateSizeOfAlignOfExpr(T, E->getOperatorLoc(), isSizeOf,
|
||||
E->getSourceRange());
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Arg = Visit(E->getArgumentExpr());
|
||||
if (Arg.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
Sema::OwningExprResult Result
|
||||
= SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(),
|
||||
isSizeOf, E->getSourceRange());
|
||||
if (Result.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
Arg.release();
|
||||
return move(Result);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
TemplateExprInstantiator::VisitCXXTemporaryObjectExpr(
|
||||
CXXTemporaryObjectExpr *E) {
|
||||
QualType T = E->getType();
|
||||
if (T->isDependentType()) {
|
||||
T = SemaRef.InstantiateType(T, TemplateArgs, NumTemplateArgs,
|
||||
E->getTypeBeginLoc(), DeclarationName());
|
||||
if (T.isNull())
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
llvm::SmallVector<Expr *, 16> Args;
|
||||
Args.reserve(E->getNumArgs());
|
||||
bool Invalid = false;
|
||||
for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(),
|
||||
ArgEnd = E->arg_end();
|
||||
Arg != ArgEnd; ++Arg) {
|
||||
OwningExprResult InstantiatedArg = Visit(*Arg);
|
||||
if (InstantiatedArg.isInvalid()) {
|
||||
Invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Args.push_back((Expr *)InstantiatedArg.release());
|
||||
}
|
||||
|
||||
if (!Invalid) {
|
||||
SourceLocation CommaLoc;
|
||||
// FIXME: HACK!
|
||||
if (Args.size() > 1)
|
||||
CommaLoc
|
||||
= SemaRef.PP.getLocForEndOfToken(Args[0]->getSourceRange().getEnd());
|
||||
Sema::ExprResult Result
|
||||
= SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()
|
||||
/*, FIXME*/),
|
||||
T.getAsOpaquePtr(),
|
||||
/*FIXME*/E->getTypeBeginLoc(),
|
||||
(void**)&Args[0], Args.size(),
|
||||
/*HACK*/&CommaLoc,
|
||||
E->getSourceRange().getEnd());
|
||||
if (!Result.isInvalid())
|
||||
return SemaRef.Owned(Result);
|
||||
}
|
||||
|
||||
// Clean up the instantiated arguments.
|
||||
// FIXME: Would rather do this with RAII.
|
||||
for (unsigned Idx = 0; Idx < Args.size(); ++Idx)
|
||||
SemaRef.DeleteExpr(Args[Idx]);
|
||||
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
Sema::InstantiateExpr(Expr *E, const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs) {
|
||||
|
|
|
@ -43,3 +43,13 @@ void test_BitfieldDivide() {
|
|||
(void)sizeof(BitfieldDivide<5, 1>);
|
||||
(void)sizeof(BitfieldDivide<5, 0>); // expected-note{{in instantiation of template class 'struct BitfieldDivide<5, 0>' requested here}}
|
||||
}
|
||||
|
||||
template<typename T, T I, int J>
|
||||
struct BitfieldDep {
|
||||
int bitfield : I + J;
|
||||
};
|
||||
|
||||
void test_BitfieldDep() {
|
||||
(void)sizeof(BitfieldDep<int, 1, 5>);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue