aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Expr.h8
-rw-r--r--lib/AST/Expr.cpp30
-rw-r--r--lib/Sema/Sema.h14
-rw-r--r--lib/Sema/SemaExpr.cpp150
-rw-r--r--lib/Sema/SemaOverload.cpp150
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp146
-rw-r--r--test/SemaTemplate/instantiate-expr-1.cpp16
-rw-r--r--test/SemaTemplate/instantiate-expr-2.cpp15
8 files changed, 372 insertions, 157 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index bfd8538788..ed571fd6c4 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -660,6 +660,14 @@ public:
/// corresponds to, e.g. "sizeof" or "[pre]++"
static const char *getOpcodeStr(Opcode Op);
+ /// \brief Retrieve the unary opcode that corresponds to the given
+ /// overloaded operator.
+ static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix);
+
+ /// \brief Retrieve the overloaded operator kind that corresponds to
+ /// the given unary opcode.
+ static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
+
virtual SourceRange getSourceRange() const {
if (isPostfix())
return SourceRange(Val->getLocStart(), Loc);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4b99eefcd4..273b5ed72f 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -91,6 +91,36 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
}
}
+UnaryOperator::Opcode
+UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) {
+ switch (OO) {
+ case OO_PlusPlus: return Postfix? PostInc : PreInc;
+ case OO_MinusMinus: return Postfix? PostDec : PreDec;
+ case OO_Amp: return AddrOf;
+ case OO_Star: return Deref;
+ case OO_Plus: return Plus;
+ case OO_Minus: return Minus;
+ case OO_Tilde: return Not;
+ case OO_Exclaim: return LNot;
+ default: assert(false && "No unary operator for overloaded function");
+ }
+}
+
+OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
+ switch (Opc) {
+ case PostInc: case PreInc: return OO_PlusPlus;
+ case PostDec: case PreDec: return OO_MinusMinus;
+ case AddrOf: return OO_Amp;
+ case Deref: return OO_Star;
+ case Plus: return OO_Plus;
+ case Minus: return OO_Minus;
+ case Not: return OO_Tilde;
+ case LNot: return OO_Exclaim;
+ default: return OO_None;
+ }
+}
+
+
//===----------------------------------------------------------------------===//
// Postfix Operators.
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b29790e7b5..a86aa65aff 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -586,6 +586,11 @@ public:
SourceLocation RParenLoc,
bool &ArgumentDependentLookup);
+ OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
+ unsigned Opc,
+ FunctionSet &Functions,
+ ExprArg input);
+
OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned Opc,
FunctionSet &Functions,
@@ -1182,16 +1187,19 @@ public:
unsigned NumToks);
// Binary/Unary Operators. 'Tok' is the token for the operator.
+ OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ ExprArg InputArg);
virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
tok::TokenKind Op, ExprArg Input);
- virtual OwningExprResult
- 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);
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange);
bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R);
bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c04006cb1c..c3ae4f7f67 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4036,114 +4036,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
}
-// Unary Operators. 'Tok' is the token for the operator.
-Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
- tok::TokenKind Op, ExprArg input) {
- // FIXME: Input is modified later, but smart pointer not reassigned.
- Expr *Input = (Expr*)input.get();
- UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
-
- if (getLangOptions().CPlusPlus &&
- (Input->getType()->isRecordType()
- || Input->getType()->isEnumeralType())) {
- // Determine which overloaded operator we're dealing with.
- static const OverloadedOperatorKind OverOps[] = {
- OO_None, OO_None,
- OO_PlusPlus, OO_MinusMinus,
- OO_Amp, OO_Star,
- OO_Plus, OO_Minus,
- OO_Tilde, OO_Exclaim,
- OO_None, OO_None,
- OO_None,
- OO_None
- };
- OverloadedOperatorKind OverOp = OverOps[Opc];
-
- // Add the appropriate overloaded operators (C++ [over.match.oper])
- // to the candidate set.
- OverloadCandidateSet CandidateSet;
- if (OverOp != OO_None)
- AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet);
-
- // Perform overload resolution.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
- case OR_Success: {
- // We found a built-in operator or an overloaded operator.
- FunctionDecl *FnDecl = Best->Function;
-
- if (FnDecl) {
- // We matched an overloaded operator. Build a call to that
- // operator.
-
- // Convert the arguments.
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (PerformObjectArgumentInitialization(Input, Method))
- return ExprError();
- } else {
- // Convert the arguments.
- if (PerformCopyInitialization(Input,
- FnDecl->getParamDecl(0)->getType(),
- "passing"))
- return ExprError();
- }
-
- // Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
-
- // Build the actual expression node.
- Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
- SourceLocation());
- UsualUnaryConversions(FnExpr);
-
- input.release();
- return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
- &Input, 1, ResultTy,
- OpLoc));
- } else {
- // We matched a built-in operator. Convert the arguments, then
- // break out so that we will build the appropriate built-in
- // operator node.
- if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], "passing"))
- return ExprError();
-
- break;
- }
- }
-
- case OR_No_Viable_Function:
- // No viable function; fall through to handling this as a
- // built-in operator, which will produce an error message for us.
- break;
-
- case OR_Ambiguous:
- Diag(OpLoc, diag::err_ovl_ambiguous_oper)
- << UnaryOperator::getOpcodeStr(Opc)
- << Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return ExprError();
-
- case OR_Deleted:
- Diag(OpLoc, diag::err_ovl_deleted_oper)
- << Best->Function->isDeleted()
- << UnaryOperator::getOpcodeStr(Opc)
- << Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
- return ExprError();
- }
-
- // Either we found no viable overloaded operator or we matched a
- // built-in operator. In either case, fall through to trying to
- // build a built-in operation.
- }
-
+Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ ExprArg InputArg) {
+ UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
+
+ // FIXME: Input is modified below, but InputArg is not updated
+ // appropriately.
+ Expr *Input = (Expr *)InputArg.get();
QualType resultType;
switch (Opc) {
- default:
- assert(0 && "Unimplemented unary expr!");
+ case UnaryOperator::PostInc:
+ case UnaryOperator::PostDec:
+ case UnaryOperator::OffsetOf:
+ assert(false && "Invalid unary operator");
+ break;
+
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
@@ -4211,10 +4119,38 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
}
if (resultType.isNull())
return ExprError();
- input.release();
+
+ InputArg.release();
return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc));
}
+// Unary Operators. 'Tok' is the token for the operator.
+Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Op, ExprArg input) {
+ Expr *Input = (Expr*)input.get();
+ UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+
+ if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) {
+ // Find all of the overloaded operators visible from this
+ // point. We perform both an operator-name lookup from the local
+ // scope and an argument-dependent lookup based on the types of
+ // the arguments.
+ FunctionSet Functions;
+ OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc);
+ if (OverOp != OO_None) {
+ LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(),
+ Functions);
+ DeclarationName OpName
+ = Context.DeclarationNames.getCXXOperatorName(OverOp);
+ ArgumentDependentLookup(OpName, &Input, 1, Functions);
+ }
+
+ return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input));
+ }
+
+ return CreateBuiltinUnaryOp(OpLoc, Opc, move(input));
+}
+
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
SourceLocation LabLoc,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 865034707d..8943aa602e 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -3623,6 +3623,153 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
return 0;
}
+/// \brief Create a unary operation that may resolve to an overloaded
+/// operator.
+///
+/// \param OpLoc The location of the operator itself (e.g., '*').
+///
+/// \param OpcIn The UnaryOperator::Opcode that describes this
+/// operator.
+///
+/// \param Functions The set of non-member functions that will be
+/// considered by overload resolution. The caller needs to build this
+/// set based on the context using, e.g.,
+/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
+/// set should not contain any member functions; those will be added
+/// by CreateOverloadedUnaryOp().
+///
+/// \param input The input argument.
+Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
+ unsigned OpcIn,
+ FunctionSet &Functions,
+ ExprArg input) {
+ UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn);
+ Expr *Input = (Expr *)input.get();
+
+ OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc);
+ assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+
+ Expr *Args[2] = { Input, 0 };
+ unsigned NumArgs = 1;
+
+ // For post-increment and post-decrement, add the implicit '0' as
+ // the second argument, so that we know this is a post-increment or
+ // post-decrement.
+ if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) {
+ llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
+ Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy,
+ SourceLocation());
+ NumArgs = 2;
+ }
+
+ if (Input->isTypeDependent()) {
+ OverloadedFunctionDecl *Overloads
+ = OverloadedFunctionDecl::Create(Context, CurContext, OpName);
+ for (FunctionSet::iterator Func = Functions.begin(),
+ FuncEnd = Functions.end();
+ Func != FuncEnd; ++Func)
+ Overloads->addOverload(*Func);
+
+ DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
+ OpLoc, false, false);
+
+ input.release();
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
+ &Args[0], NumArgs,
+ Context.DependentTy,
+ OpLoc));
+ }
+
+ // Build an empty overload set.
+ OverloadCandidateSet CandidateSet;
+
+ // Add the candidates from the given function set.
+ AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false);
+
+ // Add operator candidates that are member functions.
+ AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet);
+
+ // Add builtin operator candidates.
+ AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, CandidateSet);
+
+ // Perform overload resolution.
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success: {
+ // We found a built-in operator or an overloaded operator.
+ FunctionDecl *FnDecl = Best->Function;
+
+ if (FnDecl) {
+ // We matched an overloaded operator. Build a call to that
+ // operator.
+
+ // Convert the arguments.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
+ if (PerformObjectArgumentInitialization(Input, Method))
+ return ExprError();
+ } else {
+ // Convert the arguments.
+ if (PerformCopyInitialization(Input,
+ FnDecl->getParamDecl(0)->getType(),
+ "passing"))
+ return ExprError();
+ }
+
+ // Determine the result type
+ QualType ResultTy
+ = FnDecl->getType()->getAsFunctionType()->getResultType();
+ ResultTy = ResultTy.getNonReferenceType();
+
+ // Build the actual expression node.
+ Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
+ SourceLocation());
+ UsualUnaryConversions(FnExpr);
+
+ input.release();
+ return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
+ &Input, 1, ResultTy,
+ OpLoc));
+ } else {
+ // We matched a built-in operator. Convert the arguments, then
+ // break out so that we will build the appropriate built-in
+ // operator node.
+ if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
+ Best->Conversions[0], "passing"))
+ return ExprError();
+
+ break;
+ }
+ }
+
+ case OR_No_Viable_Function:
+ // No viable function; fall through to handling this as a
+ // built-in operator, which will produce an error message for us.
+ break;
+
+ case OR_Ambiguous:
+ Diag(OpLoc, diag::err_ovl_ambiguous_oper)
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Input->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+
+ case OR_Deleted:
+ Diag(OpLoc, diag::err_ovl_deleted_oper)
+ << Best->Function->isDeleted()
+ << UnaryOperator::getOpcodeStr(Opc)
+ << Input->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ return ExprError();
+ }
+
+ // Either we found no viable overloaded operator or we matched a
+ // built-in operator. In either case, fall through to trying to
+ // build a built-in operation.
+ input.release();
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Owned(Input));
+}
+
/// \brief Create a binary operation that may resolve to an overloaded
/// operator.
///
@@ -3645,7 +3792,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned OpcIn,
FunctionSet &Functions,
Expr *LHS, Expr *RHS) {
- OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHS, RHS };
BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
@@ -3688,6 +3834,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
!LHS->getType()->isOverloadableType())
return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
+ // Build an empty overload set.
+ OverloadCandidateSet CandidateSet;
// Add the candidates from the given function set.
AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 4bd7ad4e83..4c3f100d74 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -584,6 +584,7 @@ namespace {
OwningExprResult VisitIntegerLiteral(IntegerLiteral *E);
OwningExprResult VisitDeclRefExpr(DeclRefExpr *E);
OwningExprResult VisitParenExpr(ParenExpr *E);
+ OwningExprResult VisitUnaryOperator(UnaryOperator *E);
OwningExprResult VisitBinaryOperator(BinaryOperator *E);
OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
OwningExprResult VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
@@ -634,6 +635,17 @@ TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) {
}
Sema::OwningExprResult
+TemplateExprInstantiator::VisitUnaryOperator(UnaryOperator *E) {
+ Sema::OwningExprResult Arg = Visit(E->getSubExpr());
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(),
+ E->getOpcode(),
+ move(Arg));
+}
+
+Sema::OwningExprResult
TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
Sema::OwningExprResult LHS = Visit(E->getLHS());
if (LHS.isInvalid())
@@ -658,74 +670,116 @@ TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
Sema::OwningExprResult
TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
- // FIXME: Only handles binary operators at the moment.
-
- Sema::OwningExprResult LHS = Visit(E->getArg(0));
- if (LHS.isInvalid())
+ Sema::OwningExprResult First = Visit(E->getArg(0));
+ if (First.isInvalid())
return SemaRef.ExprError();
- Sema::OwningExprResult RHS = Visit(E->getArg(1));
- if (RHS.isInvalid())
- return SemaRef.ExprError();
+ Expr *Args[2] = { (Expr *)First.get(), 0 };
+
+ Sema::OwningExprResult Second(SemaRef);
+ if (E->getNumArgs() == 2) {
+ Second = Visit(E->getArg(1));
+
+ if (Second.isInvalid())
+ return SemaRef.ExprError();
- Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get();
- Expr *Args[2] = { lhs, rhs };
+ Args[1] = (Expr *)Second.get();
+ }
if (!E->isTypeDependent()) {
// Since our original expression was not type-dependent, we do not
// perform lookup again at instantiation time (C++ [temp.dep]p1).
// Instead, we just build the new overloaded operator call
// expression.
- LHS.release();
- RHS.release();
+ First.release();
+ Second.release();
return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
SemaRef.Context,
E->getOperator(),
E->getCallee(),
- Args, 2, E->getType(),
+ Args, E->getNumArgs(),
+ E->getType(),
E->getOperatorLoc()));
}
- BinaryOperator::Opcode Opc =
- BinaryOperator::getOverloadedOpcode(E->getOperator());
- Sema::OwningExprResult Result(SemaRef);
- if (!lhs->getType()->isOverloadableType() &&
- !rhs->getType()->isOverloadableType()) {
- // Neither LHS nor RHS is an overloadable type, so try create a
- // built-in binary operation.
- Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc,
- lhs, rhs);
+ bool isPostIncDec = E->getNumArgs() == 2 &&
+ (E->getOperator() == OO_PlusPlus || E->getOperator() == OO_MinusMinus);
+ if (E->getNumArgs() == 1 || isPostIncDec) {
+ if (!Args[0]->getType()->isOverloadableType()) {
+ // The argument is not of overloadable type, so try to create a
+ // built-in unary operation.
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
+
+ return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), Opc,
+ move(First));
+ }
+
+ // Fall through to perform overload resolution
} else {
- // Compute the set of functions that were found at template
- // definition time.
- Sema::FunctionSet Functions;
- 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();
- F != FEnd; ++F)
- Functions.insert(*F);
-
- // Add any functions found via argument-dependent lookup.
- DeclarationName OpName
- = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
- SemaRef.ArgumentDependentLookup(OpName, Args, 2, Functions);
-
- // Create the overloaded operator.
- Result = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc,
- Functions, lhs, rhs);
+ assert(E->getNumArgs() == 2 && "Expected binary operation");
+
+ Sema::OwningExprResult Result(SemaRef);
+ if (!Args[0]->getType()->isOverloadableType() &&
+ !Args[1]->getType()->isOverloadableType()) {
+ // Neither of the arguments is an overloadable type, so try to
+ // create a built-in binary operation.
+ BinaryOperator::Opcode Opc =
+ BinaryOperator::getOverloadedOpcode(E->getOperator());
+ Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc,
+ Args[0], Args[1]);
+ if (Result.isInvalid())
+ return SemaRef.ExprError();
+
+ First.release();
+ Second.release();
+ return move(Result);
+ }
+
+ // Fall through to perform overload resolution.
}
+ // Compute the set of functions that were found at template
+ // definition time.
+ Sema::FunctionSet Functions;
+ 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();
+ F != FEnd; ++F)
+ Functions.insert(*F);
+
+ // Add any functions found via argument-dependent lookup.
+ DeclarationName OpName
+ = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
+ SemaRef.ArgumentDependentLookup(OpName, Args, E->getNumArgs(), Functions);
+
+ // Create the overloaded operator invocation.
+ if (E->getNumArgs() == 1 || isPostIncDec) {
+ UnaryOperator::Opcode Opc
+ = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
+ return SemaRef.CreateOverloadedUnaryOp(E->getOperatorLoc(), Opc,
+ Functions, move(First));
+ }
+
+ // FIXME: This would be far less ugly if CreateOverloadedBinOp took
+ // in ExprArg arguments!
+ BinaryOperator::Opcode Opc =
+ BinaryOperator::getOverloadedOpcode(E->getOperator());
+ OwningExprResult Result
+ = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc,
+ Functions, Args[0], Args[1]);
+
if (Result.isInvalid())
return SemaRef.ExprError();
- LHS.release();
- RHS.release();
+ First.release();
+ Second.release();
return move(Result);
}
diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp
index 869d558e33..2ea0641b00 100644
--- a/test/SemaTemplate/instantiate-expr-1.cpp
+++ b/test/SemaTemplate/instantiate-expr-1.cpp
@@ -53,3 +53,19 @@ void test_BitfieldDep() {
(void)sizeof(BitfieldDep<int, 1, 5>);
}
+template<int I>
+struct BitfieldNeg {
+ int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}}
+};
+
+template<typename T, T I>
+struct BitfieldNeg2 {
+ int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}}
+};
+
+void test_BitfieldNeg() {
+ (void)sizeof(BitfieldNeg<-5>); // okay
+ (void)sizeof(BitfieldNeg<5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg<5>' requested here}}
+ (void)sizeof(BitfieldNeg2<int, -5>); // okay
+ (void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' requested here}}
+}
diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp
index 81af5730de..d90cef5a0b 100644
--- a/test/SemaTemplate/instantiate-expr-2.cpp
+++ b/test/SemaTemplate/instantiate-expr-2.cpp
@@ -50,3 +50,18 @@ void test_bin_op_overload(A<1> *a1, A<2> *a2, A<4> *a4, A<8> *a8) {
ZZ *zz = a8;
}
+namespace N3 {
+ eight_bytes operator-(::N3::Z);
+}
+
+namespace N4 {
+ template<typename T>
+ struct UnaryOpOverload {
+ typedef A<sizeof(-T())> type;
+ };
+}
+
+void test_unary_op_overload(A<8> *a8) {
+ typedef N4::UnaryOpOverload<N3::Z>::type UZ;
+ UZ *uz = a8;
+}