From fac1ba39e6176beb4d38f9fc3a34744ec2b5e18d Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Sun, 3 Nov 2019 00:54:28 -0400 Subject: [PATCH] Bug 536986 - Add support for string literal operator templates This was proposed for standardization in N3599. The proposal was not accepted, but it's supported by gcc and clang as an extension. Change-Id: I0c4a6e532f3a9172a8cb26218f0a608a1ca6be7d --- .../parser/tests/ast2/AST2TemplateTests.java | 12 +++++ .../parser/cpp/semantics/CPPSemantics.java | 45 ++++++++++++++++--- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 242b5ed5eb5..bada355b7d4 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -11373,4 +11373,16 @@ public class AST2TemplateTests extends AST2CPPTestBase { public void testGlobalConstWorksAsConstExpression_545756() throws Exception { parseAndCheckBindings(); } + + // template + // unsigned int operator""_test() { + // return sizeof...(Chars); + // } + // + // void foo() { + // auto len = "test"_test; + // } + public void testStringLiteralOperatorTemplate_536986() throws Exception { + parseAndCheckImplicitNameBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index bcb87fc8d92..02046bca740 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -231,6 +231,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownField; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMethod; @@ -3453,11 +3454,10 @@ public class CPPSemantics { data.setFunctionArguments(false, createArgForType(exp, charArray)); ret = resolveFunction(data, funcs, true, false); - // char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator // The string literal is passed to the operator as chars: - // "literal"_op -> operator "" _op<'l', 'i', 't', 'e', 'r', 'a', 'l'>(); + // 12345_op -> operator "" _op<'1', '2', '3', '4', '5'>(); ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length]; for (int k = 0; k < stringLiteral.length; k++) { args[k] = new CPPTemplateNonTypeArgument( @@ -3492,13 +3492,48 @@ public class CPPSemantics { * str (i.e., its length excluding the terminating null character). * L is treated as operator "" X(str, len) */ - CPPPointerType strType = new CPPPointerType( - new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null), true, false, - false); + IType charType = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, null); + CPPPointerType strType = new CPPPointerType(charType, true, false, false); IASTInitializerClause[] initializer = new IASTInitializerClause[] { createArgForType(exp, strType), createArgForType(null, CPPBasicType.UNSIGNED_INT) }; data.setFunctionArguments(false, initializer); ret = resolveFunction(data, funcs, true, false); + + // GNU extension: allow literal operator templates for string literals. + // The implementation follows the proposed spec in + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3599.html. + char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator + + // The operator template is expected to take the character type as its first argument, + // followed by the characters as non-type arguments. + // "literal"_op -> operator "" _op(); + ICPPTemplateArgument args[] = new ICPPTemplateArgument[stringLiteral.length + 1]; + args[0] = new CPPTemplateTypeArgument(charType); + for (int k = 0; k < stringLiteral.length; k++) { + args[k + 1] = new CPPTemplateNonTypeArgument( + new EvalFixed(CPPBasicType.CHAR, PRVALUE, IntegralValue.create(stringLiteral[k]))); + } + + data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp); + IBinding litTpl = resolveFunction(data, tplFunctions, true, false); + + // Do we have valid template and non-template bindings? + if (ret != null && !(ret instanceof IProblemBinding)) { + // Do we have valid template and non-template bindings? + if (litTpl instanceof ICPPFunctionInstance) { + // Ambiguity? It has two valid options, and the spec says it shouldn't + return new ProblemBinding(data.getLookupName(), exp, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, + tplFunctions); + } + } else { + if (litTpl instanceof ICPPFunctionInstance) { + // Only the template binding is valid + ret = litTpl; + } else { + // Couldn't find a valid operator + return ret; + } + } } else if (kind == IASTLiteralExpression.lk_char_constant) { /* * 2.14.8.6