1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +02:00

Bug 302412: Template argument deduction for initializer lists.

This commit is contained in:
Markus Schorn 2010-03-12 13:52:28 +00:00
parent 83736061cd
commit 477c241751
4 changed files with 85 additions and 7 deletions

View file

@ -8118,12 +8118,14 @@ public class AST2CPPTests extends AST2BaseTest {
// namespace std {
// template<typename T> class initializer_list;
// }
// void f(std::initializer_list<int>);
// //void ff(std::initializer_list<str>);
// struct str {
// str(const char*);
// };
// struct A {
// A(std::initializer_list<double>); // #1
// A(std::initializer_list<const char*>); // #3
// A(std::initializer_list<str>); // #3
// };
// void f(std::initializer_list<int>);
// void g(A);
// void test() {
// f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion
@ -8213,5 +8215,27 @@ public class AST2CPPTests extends AST2BaseTest {
// not detected by CDT
// bh.assertProblem("f( {1.0} )", 1);
}
// namespace std {
// template<typename T> class initializer_list;
// }
// void g(const double &);
// void h(int);
// void test() {
// g({1}); // same conversion as int to double
//
// h( {'a'} ); // OK: same conversion as char to int
// h( {1.0} ); // error: narrowing
// h( { } ); // OK: identity conversion
// }
public void testListInitialization_302412e() throws Exception {
String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
// not detected by CDT
// bh.assertProblem("g({1})", 1);
bh.assertNonProblem("h( {'a'} )", 1);
bh.assertProblem("h( {1.0} )", 1);
bh.assertNonProblem("h( { } )", 1);
}
}

View file

@ -4876,4 +4876,25 @@ public class AST2TemplateTests extends AST2BaseTest {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
// namespace std {
// template<typename T> class initializer_list;
// }
// template<class T> void f(std::initializer_list<T>);
// template<class T> void g(T);
// void test() {
// f({1,2,3}); // T deduced to int
// f({1,"asdf"}); // error: T deduced to both int and const char*
// g({1,2,3}); // error: no argument deduced for T
// }
public void testTypeDeductForInitLists_302412() throws Exception {
final String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
ICPPTemplateInstance inst;
inst= bh.assertNonProblem("f({1,2,3})", 1);
assertEquals("<int>", ASTTypeUtil.getArgumentListString(inst.getTemplateArguments(), true));
bh.assertProblem("f({1,\"asdf\"})", 1);
bh.assertProblem("g({1,2,3})", 1);
}
}

View file

@ -37,7 +37,6 @@ import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
@ -202,7 +201,7 @@ public class Conversions {
if (!isImpliedObjectType) {
if (isReferenceRelated(T1, T2) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
Cost cost= nonReferenceConversion(exprIsLValue, cv2T2, T1, udc, false);
if (!isImplicitWithoutRefQualifier) {
if (!isImplicitWithoutRefQualifier && cost.converts()) {
cost.setReferenceBinding(isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE);
}
return cost;
@ -322,11 +321,27 @@ public class Conversions {
}
return checkUserDefinedConversionSequence(false, arg, target, udc == UDCMode.deferUDC);
}
IASTInitializerClause[] args = arg.getInitializerList().getClauses();
if (args.length == 1) {
final IASTInitializerClause firstArg = args[0];
if (firstArg instanceof IASTExpression) {
IASTExpression expr= (IASTExpression) firstArg;
Cost cost= checkImplicitConversionSequence(target, expr.getExpressionType(), expr.isLValue(), udc, false);
if (cost.isNarrowingConversion()) {
return Cost.NO_CONVERSION;
}
return cost;
}
} else if (args.length == 0) {
return new Cost(arg, target, Rank.IDENTITY);
}
return Cost.NO_CONVERSION;
}
private static IType getInitListType(IType target) throws DOMException {
if (target instanceof ICPPClassSpecialization && target instanceof ICPPTemplateInstance) {
static IType getInitListType(IType target) throws DOMException {
if (target instanceof ICPPClassType && target instanceof ICPPTemplateInstance) {
ICPPTemplateInstance inst = (ICPPTemplateInstance) target;
if (CharArrayUtils.equals(INITIALIZER_LIST_NAME, inst.getNameCharArray())) {
IBinding owner = inst.getOwner();

View file

@ -190,6 +190,24 @@ public class TemplateArgumentDeduction {
boolean isReferenceTypeParameter= false;
IType arg = fnArgs[j];
par= SemanticUtil.getNestedType(par, SemanticUtil.TDEF); // adjustParameterType preserves typedefs
// C++0x: 14.9.2.1-1
if (arg instanceof InitializerListType) {
assert !checkExactMatch;
par= SemanticUtil.getNestedType(par, TDEF | REF | CVTYPE);
// Check if this is a deduced context
IType inner= Conversions.getInitListType(par);
if (inner != null) {
IType[] types = ((InitializerListType) arg).getExpressionTypes();
for (IType iType : types) {
if (!deduct.fromType(inner, iType))
return false;
}
}
continue;
}
// 14.8.2.1-2
if (par instanceof ICPPReferenceType) {
// If P is an rvalue reference to a cv-unqualified template parameter and the argument is an