diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 8 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 62 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 40 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 38 | ||||
-rw-r--r-- | test/SemaTemplate/resolve-single-template-id.patch | 68 |
6 files changed, 168 insertions, 58 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 17e9d3d696..c92bf5984d 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1289,6 +1289,14 @@ public: bool Complain = false, DeclAccessPair* Found = 0); + ExprResult ResolveAndFixSingleFunctionTemplateSpecialization( + Expr *SrcExpr, bool DoFunctionPointerConverion = false, + bool Complain = false, + const SourceRange& OpRangeForComplaining = SourceRange(), + QualType DestTypeForComplaining = QualType(), + unsigned DiagIDForComplaining = 0); + + Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, FunctionDecl *Fn); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index d09f20e113..422b915b68 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -527,7 +527,15 @@ ExprResult Parser::ParseCXXTypeid() { RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); if (RParenLoc.isInvalid()) return ExprError(); - + + // If we are a foo<int> that identifies a single function, resolve it now... + Expr* e = Result.get(); + if (e->getType() == Actions.Context.OverloadTy) { + ExprResult er = + Actions.ResolveAndFixSingleFunctionTemplateSpecialization(e); + if (er.isUsable()) + Result = er.release(); + } Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.release(), RParenLoc); } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 5b28bc3d9f..557d27a943 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -128,17 +128,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, CastKind &Kind); -static ExprResult -ResolveAndFixSingleFunctionTemplateSpecialization( - Sema &Self, Expr *SrcExpr, - bool DoFunctionPointerConverion = false, - bool Complain = false, - const SourceRange& OpRangeForComplaining = SourceRange(), - QualType DestTypeForComplaining = QualType(), - unsigned DiagIDForComplaining = 0); - - - /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -617,7 +606,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, Self.IgnoredValueConversions(SrcExpr); if (SrcExpr->getType() == Self.Context.OverloadTy) { ExprResult SingleFunctionExpression = - ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr, false, // Decay Function to ptr true, // Complain OpRange, DestType, diag::err_bad_static_cast_overload); @@ -1260,41 +1249,8 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Success; } -// A helper function to resolve and fix an overloaded expression that -// can be resolved because it identifies a single function -// template specialization -// Last three arguments should only be supplied if Complain = true -static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization( - Sema &Self, Expr *SrcExpr, - bool DoFunctionPointerConverion, - bool Complain, - const SourceRange& OpRangeForComplaining, - QualType DestTypeForComplaining, - unsigned DiagIDForComplaining) { - assert(SrcExpr->getType() == Self.Context.OverloadTy); - DeclAccessPair Found; - Expr* SingleFunctionExpression = 0; - if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization( - SrcExpr, false, // false -> Complain - &Found)) { - if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) { - // mark the expression as resolved to Fn - SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr, - Found, Fn); - - if (DoFunctionPointerConverion) - Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression); - } - } - if (!SingleFunctionExpression && Complain) { - OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; - Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining) - << oe->getName() << DestTypeForComplaining << OpRangeForComplaining - << oe->getQualifierLoc().getSourceRange(); - Self.NoteAllOverloadCandidates(SrcExpr); - } - return SingleFunctionExpression; -} + + static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, @@ -1311,7 +1267,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, if (SrcType == Self.Context.OverloadTy) { // ... unless foo<int> resolves to an lvalue unambiguously ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr, Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr ); if (SingleFunctionExpr.isUsable()) { @@ -1544,11 +1500,11 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, bool ret = false; // false is 'able to convert' if (CastExpr->getType() == Context.OverloadTy) { ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization(*this, - CastExpr, - /* Decay Function to ptr */ false, - /* Complain */ true, - R, CastTy, diag::err_bad_cstyle_cast_overload); + ResolveAndFixSingleFunctionTemplateSpecialization( + CastExpr, /* Decay Function to ptr */ false, + /* Complain */ true, R, CastTy, + diag::err_bad_cstyle_cast_overload); + if (SingleFunctionExpr.isUsable()) { CastExpr = SingleFunctionExpr.release(); Kind = CK_ToVoid; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8a532f0363..546d2e7e38 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5321,9 +5321,10 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { - // If both LHS and RHS are overloaded functions, try to resolve them. - if (Context.hasSameType(LHS->getType(), RHS->getType()) && - LHS->getType()->isSpecificBuiltinType(BuiltinType::Overload)) { + + // If either LHS or RHS are overloaded functions, try to resolve them. + if (LHS->getType() == Context.OverloadTy || + RHS->getType() == Context.OverloadTy) { ExprResult LHSResult = CheckPlaceholderExpr(LHS, QuestionLoc); if (LHSResult.isInvalid()) return QualType(); @@ -6313,6 +6314,10 @@ QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { Diag(Loc, diag::err_typecheck_invalid_operands) << lex->getType() << rex->getType() << lex->getSourceRange() << rex->getSourceRange(); + if (lex->getType() == Context.OverloadTy) + NoteAllOverloadCandidates(lex); + if (rex->getType() == Context.OverloadTy) + NoteAllOverloadCandidates(rex); return QualType(); } @@ -6789,12 +6794,14 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, QualType lType = lex->getType(); QualType rType = rex->getType(); - + Expr *LHSStripped = lex->IgnoreParenImpCasts(); Expr *RHSStripped = rex->IgnoreParenImpCasts(); QualType LHSStrippedType = LHSStripped->getType(); QualType RHSStrippedType = RHSStripped->getType(); + + // Two different enums will raise a warning when compared. if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) { if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) { @@ -8033,6 +8040,26 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; + // Check if a 'foo<int>' involved in a binary op, identifies a single + // function unambiguously (i.e. an lvalue ala 13.4) + // But since an assignment can trigger target based overload, exclude it in + // our blind search. i.e: + // template<class T> void f(); template<class T, class U> void f(U); + // f<int> == 0; // resolve f<int> blindly + // void (*p)(int); p = f<int>; // resolve f<int> using target + if (Opc != BO_Assign) { + if (lhs->getType() == Context.OverloadTy) { + ExprResult resolvedLHS = + ResolveAndFixSingleFunctionTemplateSpecialization(lhs); + if (resolvedLHS.isUsable()) lhs = resolvedLHS.release(); + } + if (rhs->getType() == Context.OverloadTy) { + ExprResult resolvedRHS = + ResolveAndFixSingleFunctionTemplateSpecialization(rhs); + if (resolvedRHS.isUsable()) rhs = resolvedRHS.release(); + } + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); @@ -8390,6 +8417,11 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = CheckAddressOfOperand(*this, Input, OpLoc); break; case UO_Deref: + if (Input->getType() == Context.OverloadTy ) { + ExprResult er = ResolveAndFixSingleFunctionTemplateSpecialization(Input); + if (er.isUsable()) + Input = er.release(); + } DefaultFunctionArrayLvalueConversion(Input); resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc); break; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index bf24b74848..d746c7bb1e 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -7490,6 +7490,44 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, return Matched; } + + + +// Resolve and fix an overloaded expression that +// can be resolved because it identifies a single function +// template specialization +// Last three arguments should only be supplied if Complain = true +ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( + Expr *SrcExpr, bool DoFunctionPointerConverion, bool Complain, + const SourceRange& OpRangeForComplaining, + QualType DestTypeForComplaining, + unsigned DiagIDForComplaining ) { + + assert(SrcExpr->getType() == Context.OverloadTy); + + DeclAccessPair Found; + Expr* SingleFunctionExpression = 0; + if (FunctionDecl* Fn = ResolveSingleFunctionTemplateSpecialization( + SrcExpr, false, // false -> Complain + &Found)) { + if (!DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) { + // mark the expression as resolved to Fn + SingleFunctionExpression = FixOverloadedFunctionReference(SrcExpr, + Found, Fn); + if (DoFunctionPointerConverion) + DefaultFunctionArrayLvalueConversion(SingleFunctionExpression); + } + } + if (!SingleFunctionExpression && Complain) { + OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; + Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining) + << oe->getName() << DestTypeForComplaining << OpRangeForComplaining + << oe->getQualifierLoc().getSourceRange(); + NoteAllOverloadCandidates(SrcExpr); + } + return SingleFunctionExpression; +} + /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, DeclAccessPair FoundDecl, diff --git a/test/SemaTemplate/resolve-single-template-id.patch b/test/SemaTemplate/resolve-single-template-id.patch new file mode 100644 index 0000000000..8be2f6c65f --- /dev/null +++ b/test/SemaTemplate/resolve-single-template-id.patch @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s +//#include <typeinfo> +void one() { } +void two() { } // expected-note 3{{candidate}} +void two(int) { } // expected-note 3{{candidate}} + +template<class T> void twoT() { } // expected-note 4{{candidate}} +template<class T> void twoT(int) { } // expected-note 4{{candidate}} + +template<class T> void oneT() { } +template<class T, class U> void oneT(U) { } +/* +The target can be + an object or reference being initialized (8.5, 8.5.3), + the left side of an assignment (5.17), + a parameter of a function (5.2.2), + a parameter of a user-defined operator (13.5), + the return value of a function, operator function, or conversion (6.6.3), + an explicit type conversion (5.2.3, 5.2.9, 5.4), or + a non-type template-parameter (14.3.2) +*/ +//#include <typeinfo> +template<void (*p)(int)> struct test { }; + +int main() +{ + one; // expected-warning {{expression result unused}} + two; // expected-error {{address of overloaded}} + oneT<int>; // expected-warning {{expression result unused}} + twoT<int>; // expected-error {{address of overloaded}} + typeid(oneT<int>); //expected-error {{you need to include <typeinfo>}} + sizeof(oneT<int>); // expected-warning {{expression result unused}} + sizeof(twoT<int>); //expected-error {{cannot resolve overloaded function from context}} + decltype(oneT<int>)* fun = 0; + + *one; // expected-warning {{expression result unused}} + *oneT<int>; // expected-warning {{expression result unused}} + *two; //expected-error {{cannot resolve overloaded function from context}} + *twoT<int>; //expected-error {{cannot resolve overloaded function from context}} + !oneT<int>; // expected-warning {{expression result unused}} + +oneT<int>; // expected-warning {{expression result unused}} + -oneT<int>; //expected-error {{invalid argument type}} + oneT<int> == 0; // expected-warning {{expression result unused}} + 0 == oneT<int>; // expected-warning {{expression result unused}} + 0 != oneT<int>; // expected-warning {{expression result unused}} + (false ? one : oneT<int>); // expected-warning {{expression result unused}} + void (*p1)(int); p1 = oneT<int>; + + int i = (int) (false ? (void (*)(int))twoT<int> : oneT<int>); //expected-error {{incompatible operand}} + (twoT<int>) == oneT<int>; //expected-error {{invalid operands to binary expression}} + bool b = oneT<int>; + void (*p)() = oneT<int>; + test<oneT<int>> ti; + void (*u)(int) = oneT<int>; + + b = (void (*)()) twoT<int>; + + one < one; //expected-warning {{self-comparison always evaluates to false}} \ + //expected-warning {{expression result unused}} + + oneT<int> < oneT<int>; //expected-warning {{self-comparison always evaluates to false}} \ + //expected-warning {{expression result unused}} + + two < two; //expected-error {{invalid operands to binary expression}} + twoT<int> < twoT<int>; //expected-error {{invalid operands to binary expression}} + oneT<int> == 0; // expected-warning {{expression result unused}} + +} |