the attached patch fixes bu 18645:
http://llvm.org/bugs/show_bug.cgi?id=18645
In c++11, call deduction of a template parameter of type 'T &&' will deduce T as
lvalue reference, if the corresponding argument is an lvalue. The bug occurs
when the argument is (for instance) a template-id-expr for a template function.
At the point of checking this behaviour, the id-expr hasn't been resolved and
the modification to an lvalue ref doesn't occur. We end up deducing T as a
function type, and further never decay it to pointer to function.
It is this bit of code that's trying that test:
- if (isa<RValueReferenceType>(ParamType)) {
- if (!PointeeType.getQualifiers() &&
- isa<TemplateTypeParmType>(PointeeType) &&
- Arg->Classify(S.Context).isLValue() &&
- Arg->getType() != S.Context.OverloadTy &&
- Arg->getType() != S.Context.BoundMemberTy)
and for an arg of template-id-expr, Arg->getType () is an OverloadTy, so the
test fails.
Just after this test is the following deduction check:
if (ArgType == S.Context.OverloadTy) {
ArgType = ResolveOverloadForDeduction(S, TemplateParams,
Arg, ParamType,
ParamRefType != nullptr);
which is doing the template-id resolution needed. Now, just after that is the
following:
if (ParamRefType) {
// C++0x [temp.deduct.call]p3:
// [...] If P is of the form T&&, where T is a template parameter, and
// the argument is an lvalue, the type A& is used in place of A for
// type deduction.
if (ParamRefType->isRValueReferenceType() &&
ParamRefType->getAs<TemplateTypeParmType>() && <-- this line
Arg->isLValue())
ArgType = S.Context.getLValueReferenceType(ArgType);
which is also attempting to do the same check, but it's flubbed the wording on
the indicated line by checking ParamRefType not ParamRefType->getPointeeType ()
(aka ParamType at this point).
Just fixing that line would work, but it is unnecessary and wrong to have the
check remain in two places. Hence I removed the checking from before the call
to ResolveOverloadForDeduction and moved it all into the lower if conditional.
For good measure I moved the earlier check about incomplete array types there
too, to keep the reference parameter handling all in one place. The only piece
of this check that happens before the ROFD call is to remove the referenceness
from ParamType.
built and tested on x86_64-linux. ok?
nathan
# svn diff src
# svn diff src/projects/compiler-rt
# svn diff src/tools/clang
Index: src/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- src/tools/clang/lib/Sema/SemaTemplateDeduction.cpp (revision 225453)
+++ src/tools/clang/lib/Sema/SemaTemplateDeduction.cpp (working copy)
@@ -3133,34 +3133,16 @@ static bool AdjustFunctionParmAndArgType
// are ignored for type deduction.
if (ParamType.hasQualifiers())
ParamType = ParamType.getUnqualifiedType();
- const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
- if (ParamRefType) {
- QualType PointeeType = ParamRefType->getPointeeType();
-
- // If the argument has incomplete array type, try to complete its type.
- if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
- ArgType = Arg->getType();
-
- // [C++0x] If P is an rvalue reference to a cv-unqualified
- // template parameter and the argument is an lvalue, the type
- // "lvalue reference to A" is used in place of A for type
- // deduction.
- if (isa<RValueReferenceType>(ParamType)) {
- if (!PointeeType.getQualifiers() &&
- isa<TemplateTypeParmType>(PointeeType) &&
- Arg->Classify(S.Context).isLValue() &&
- Arg->getType() != S.Context.OverloadTy &&
- Arg->getType() != S.Context.BoundMemberTy)
- ArgType = S.Context.getLValueReferenceType(ArgType);
- }
- // [...] If P is a reference type, the type referred to by P is used
- // for type deduction.
- ParamType = PointeeType;
- }
+ // [...] If P is a reference type, the type referred to by P is
+ // used for type deduction.
+ const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
+ if (ParamRefType)
+ ParamType = ParamRefType->getPointeeType();
- // Overload sets usually make this parameter an undeduced
- // context, but there are sometimes special circumstances.
+ // Overload sets usually make this parameter an undeduced context,
+ // but there are sometimes special circumstances. Typically
+ // involving a template-id-expr.
if (ArgType == S.Context.OverloadTy) {
ArgType = ResolveOverloadForDeduction(S, TemplateParams,
Arg, ParamType,
@@ -3170,12 +3152,17 @@ static bool AdjustFunctionParmAndArgType
}
if (ParamRefType) {
- // C++0x [temp.deduct.call]p3:
- // [...] If P is of the form T&&, where T is a template parameter, and
- // the argument is an lvalue, the type A& is used in place of A for
- // type deduction.
+ // If the argument has incomplete array type, try to complete its type.
+ if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
+ ArgType = Arg->getType();
+
+ // C++0x [temp.deduct.call]p3:
+ // If P is an rvalue reference to a cv-unqualified template
+ // parameter and the argument is an lvalue, the type "lvalue
+ // reference to A" is used in place of A for type deduction.
if (ParamRefType->isRValueReferenceType() &&
- ParamRefType->getAs<TemplateTypeParmType>() &&
+ !ParamType.getQualifiers() &&
+ isa<TemplateTypeParmType>(ParamType) &&
Arg->isLValue())
ArgType = S.Context.getLValueReferenceType(ArgType);
} else {
Index: src/tools/clang/test/SemaCXX/accessible-base.cpp
===================================================================
Index: src/tools/clang/test/SemaTemplate/deduction.cpp
===================================================================
--- src/tools/clang/test/SemaTemplate/deduction.cpp (revision 225453)
+++ src/tools/clang/test/SemaTemplate/deduction.cpp (working copy)
@@ -202,3 +202,20 @@ namespace PR19372 {
using T = S<int, int>;
}
}
+
+namespace PR18645 {
+ template <typename> class Bar {};
+
+ template <typename F> struct Foo : Bar<F ()> {};
+
+ template <typename F>
+ Foo<F> Quux (F &&f); // deduce F as lvalue ref to fn
+
+ template <typename T>
+ int TPLFN (T);
+
+ void Baz (void)
+ {
+ Quux (TPLFN<float>);
+ }
+}
# svn diff src/tools/clang/tools/extra
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits