mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 442325 - Add support for __has_feature
Change-Id: I6ebbf76f19d1edde0592df0053a74006d5684d9d Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
aea96f8c1b
commit
a9a454f256
6 changed files with 169 additions and 10 deletions
|
@ -11541,5 +11541,26 @@ public class AST2CPPTests extends AST2TestBase {
|
|||
BindingAssertionHelper bh = getAssertionHelper();
|
||||
ICPPVariable test = bh.assertNonProblemOnFirstIdentifier("test");
|
||||
assertTrue(test.getType() instanceof IProblemType); // resolution is ambiguous
|
||||
}
|
||||
|
||||
// constexpr int lambdas_supported =
|
||||
// #if __has_feature(cxx_lambdas)
|
||||
// 1;
|
||||
// #else
|
||||
// 0;
|
||||
// #endif
|
||||
//
|
||||
// constexpr int generic_lambdas_supported =
|
||||
// #if __has_feature(cxx_generic_lambdas)
|
||||
// 1;
|
||||
// #else
|
||||
// 0;
|
||||
// #endif
|
||||
public void testHasFeature_442325() throws Exception {
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
helper.assertVariableValue("lambdas_supported", 1);
|
||||
// Note: when support for generic lambdas is implemented,
|
||||
// this test will need to be updated.
|
||||
helper.assertVariableValue("generic_lambdas_supported", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -778,10 +778,17 @@ public class AST2TestBase extends BaseTestCase {
|
|||
}
|
||||
|
||||
public void assertVariableType(String variableName, IType expectedType) {
|
||||
IVariable var = assertNonProblem(variableName, IVariable.class);
|
||||
IVariable var = assertNonProblem(variableName);
|
||||
assertSameType(expectedType, var.getType());
|
||||
}
|
||||
|
||||
public void assertVariableValue(String variableName, long expectedValue) {
|
||||
IVariable var = assertNonProblem(variableName);
|
||||
assertNotNull(var.getInitialValue());
|
||||
assertNotNull(var.getInitialValue().numericalValue());
|
||||
assertEquals(expectedValue, var.getInitialValue().numericalValue().longValue());
|
||||
}
|
||||
|
||||
public <T, U extends T> U assertType(T obj, Class... cs) {
|
||||
for (Class c : cs) {
|
||||
assertInstance(obj, c);
|
||||
|
|
|
@ -310,6 +310,8 @@ public class Keywords {
|
|||
public static final char[] cPRAGMA = "pragma".toCharArray();
|
||||
public static final char[] cLINE = "line".toCharArray();
|
||||
public static final char[] cDEFINED= "defined".toCharArray();
|
||||
/** @since 5.11 */
|
||||
public static final char[] c__HAS_FEATURE = "__has_feature".toCharArray();
|
||||
/** @since 5.2*/
|
||||
public static final char[] _Pragma= "_Pragma".toCharArray();
|
||||
public static final char[] cVA_ARGS= "__VA_ARGS__".toCharArray();
|
||||
|
|
|
@ -85,6 +85,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
public static final int tSPACE= IToken.FIRST_RESERVED_PREPROCESSOR + 3;
|
||||
public static final int tNOSPACE= IToken.FIRST_RESERVED_PREPROCESSOR + 4;
|
||||
public static final int tMACRO_PARAMETER= IToken.FIRST_RESERVED_PREPROCESSOR + 5;
|
||||
public static final int t__HAS_FEATURE = IToken.FIRST_RESERVED_PREPROCESSOR + 6;
|
||||
|
||||
private static final int ORIGIN_PREPROCESSOR_DIRECTIVE = OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE;
|
||||
private static final int ORIGIN_INACTIVE_CODE = OffsetLimitReachedException.ORIGIN_INACTIVE_CODE;
|
||||
|
@ -108,7 +109,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
private static final char[] ONCE = "once".toCharArray(); //$NON-NLS-1$
|
||||
|
||||
static final int NO_EXPANSION = 0x01;
|
||||
static final int PROTECT_DEFINED = 0x02;
|
||||
// Set in contexts where preprocessor intrinsics such as 'defined'
|
||||
// or '__has_feature' need to be recognized.
|
||||
static final int PROTECT_INTRINSICS = 0x02;
|
||||
static final int STOP_AT_NL = 0x04;
|
||||
static final int CHECK_NUMBERS = 0x08;
|
||||
static final int REPORT_SIGNIFICANT_MACROS = 0x10;
|
||||
|
@ -224,6 +227,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
}
|
||||
}
|
||||
|
||||
private static Set<String> sSupportedFeatures;
|
||||
|
||||
TokenSequence fInputToMacroExpansion= new TokenSequence(false);
|
||||
TokenSequence fLineInputToMacroExpansion= new TokenSequence(true);
|
||||
|
||||
|
@ -1883,7 +1888,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
scannerCtx.clearInactiveCodeMarkerToken();
|
||||
int options= STOP_AT_NL | REPORT_SIGNIFICANT_MACROS;
|
||||
if (isCondition)
|
||||
options |= PROTECT_DEFINED;
|
||||
options |= PROTECT_INTRINSICS;
|
||||
|
||||
loop: while (true) {
|
||||
Token t= internalFetchToken(scannerCtx, options, withinExpansion);
|
||||
|
@ -1899,6 +1904,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
case tDEFINED:
|
||||
options |= NO_EXPANSION;
|
||||
break;
|
||||
case t__HAS_FEATURE:
|
||||
options |= NO_EXPANSION;
|
||||
break;
|
||||
case IToken.tLPAREN:
|
||||
break;
|
||||
default:
|
||||
|
@ -1988,9 +1996,15 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
boolean withinExpansion) throws OffsetLimitReachedException {
|
||||
final boolean reportSignificant = (options & REPORT_SIGNIFICANT_MACROS) != 0;
|
||||
final char[] name= identifier.getCharImage();
|
||||
if ((options & PROTECT_DEFINED) != 0 && CharArrayUtils.equals(name, Keywords.cDEFINED)) {
|
||||
identifier.setType(tDEFINED);
|
||||
return false;
|
||||
if ((options & PROTECT_INTRINSICS) != 0) {
|
||||
if (CharArrayUtils.equals(name, Keywords.cDEFINED)) {
|
||||
identifier.setType(tDEFINED);
|
||||
return false;
|
||||
}
|
||||
if (CharArrayUtils.equals(name, Keywords.c__HAS_FEATURE)) {
|
||||
identifier.setType(t__HAS_FEATURE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PreprocessorMacro macro= fMacroDictionary.get(name);
|
||||
if (macro == null) {
|
||||
|
@ -2066,4 +2080,94 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
|| CharArrayUtils.equals(__DATE__.getNameCharArray(), name)
|
||||
|| CharArrayUtils.equals(__TIME__.getNameCharArray(), name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public static Set<String> getSupportedFeatures() {
|
||||
if (sSupportedFeatures == null) {
|
||||
sSupportedFeatures = new HashSet<>();
|
||||
|
||||
// C++98 features
|
||||
sSupportedFeatures.add("cxx_exceptions");
|
||||
sSupportedFeatures.add("cxx_rtti");
|
||||
|
||||
// C++11 features
|
||||
// missing: cxx_access_control_sfinae (needs to be tested)
|
||||
sSupportedFeatures.add("cxx_alias_templates");
|
||||
sSupportedFeatures.add("cxx_alignas");
|
||||
sSupportedFeatures.add("cxx_alignof");
|
||||
sSupportedFeatures.add("cxx_attributes");
|
||||
sSupportedFeatures.add("cxx_auto_type");
|
||||
sSupportedFeatures.add("cxx_constexpr");
|
||||
sSupportedFeatures.add("cxx_decltype");
|
||||
// missing: cxx_decltype_incomplete_return_types (needs to be tested; see bug 324096)
|
||||
sSupportedFeatures.add("cxx_default_function_template_args");
|
||||
sSupportedFeatures.add("cxx_defaulted_functions");
|
||||
sSupportedFeatures.add("cxx_delegating_constructors");
|
||||
sSupportedFeatures.add("cxx_explicit_conversions");
|
||||
sSupportedFeatures.add("cxx_generalized_initializers");
|
||||
// missing: cxx_implicit_moves (bug 327301)
|
||||
sSupportedFeatures.add("cxx_inheriting_constructors");
|
||||
sSupportedFeatures.add("cxx_inline_namespaces");
|
||||
sSupportedFeatures.add("cxx_lambdas");
|
||||
sSupportedFeatures.add("cxx_local_type_template_args");
|
||||
sSupportedFeatures.add("cxx_noexcept");
|
||||
sSupportedFeatures.add("cxx_nonstatic_member_init");
|
||||
sSupportedFeatures.add("cxx_nullptr");
|
||||
sSupportedFeatures.add("cxx_override_control");
|
||||
sSupportedFeatures.add("cxx_range_for");
|
||||
sSupportedFeatures.add("cxx_raw_string_literals");
|
||||
sSupportedFeatures.add("cxx_reference_qualified_functions");
|
||||
sSupportedFeatures.add("cxx_rvalue_references");
|
||||
sSupportedFeatures.add("cxx_static_assert");
|
||||
sSupportedFeatures.add("cxx_strong_enums");
|
||||
sSupportedFeatures.add("cxx_thread_local");
|
||||
sSupportedFeatures.add("cxx_trailing_return");
|
||||
sSupportedFeatures.add("cxx_unicode_literals");
|
||||
// missing: cxx_unrestricted_unions (bug 327299)
|
||||
sSupportedFeatures.add("cxx_user_literals");
|
||||
sSupportedFeatures.add("cxx_variadic_templates");
|
||||
|
||||
// C++14 features
|
||||
// none supported yet
|
||||
|
||||
// C11 features
|
||||
sSupportedFeatures.add("c_alignas");
|
||||
sSupportedFeatures.add("c_alignof");
|
||||
// missing: c_atomic (bug 445297)
|
||||
// missing: c_generic_selections (bug 445296)
|
||||
// missing: c_static_assert (bug 445297)
|
||||
// missing: c_thread_local (bug 445297)
|
||||
|
||||
// Type trait primitives
|
||||
// missing: has_nothrow_assign
|
||||
// missing: has_nothrow_copy
|
||||
// missing: has_nothrow_constructor
|
||||
// missing: has_trivial_assign
|
||||
sSupportedFeatures.add("has_trivial_copy");
|
||||
// missing: has_trivial_constructor
|
||||
// missing: has_trivial_destructor
|
||||
// missing: has_virtual_destructor
|
||||
sSupportedFeatures.add("is_abstract");
|
||||
sSupportedFeatures.add("is_base_of");
|
||||
sSupportedFeatures.add("is_class");
|
||||
// missing: is_constructible
|
||||
// missing: is_convertible_to
|
||||
// missing: is_destructible
|
||||
// missing: is_empty
|
||||
sSupportedFeatures.add("is_enum");
|
||||
sSupportedFeatures.add("is_final");
|
||||
// missing: is_interface_class
|
||||
// missing: is_literal
|
||||
// missing: is_nothrow_assignable
|
||||
// missing: is_nothrow_constructible
|
||||
// missing: is_nothrow_destructible
|
||||
sSupportedFeatures.add("is_pod");
|
||||
sSupportedFeatures.add("is_polymorphic");
|
||||
// missing: is_trivially_assignable
|
||||
// missing: is_trivially_constructible
|
||||
sSupportedFeatures.add("is_union");
|
||||
sSupportedFeatures.add("underlying_type");
|
||||
}
|
||||
return sSupportedFeatures;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,6 +258,8 @@ public class ExpressionEvaluator {
|
|||
return 0;
|
||||
case CPreprocessor.tDEFINED:
|
||||
return handleDefined();
|
||||
case CPreprocessor.t__HAS_FEATURE:
|
||||
return handleHasFeature();
|
||||
case IToken.tLPAREN:
|
||||
consume();
|
||||
long r1 = expression();
|
||||
|
@ -323,6 +325,25 @@ public class ExpressionEvaluator {
|
|||
return result;
|
||||
}
|
||||
|
||||
private long handleHasFeature() throws EvalException {
|
||||
consume(); // '__has_feature'
|
||||
if (LA() != IToken.tLPAREN) {
|
||||
throw new EvalException(IProblem.SCANNER_EXPRESSION_SYNTAX_ERROR, null);
|
||||
}
|
||||
consume(); // opening parenthesis
|
||||
if (LA() != IToken.tIDENTIFIER) {
|
||||
throw new EvalException(IProblem.SCANNER_EXPRESSION_SYNTAX_ERROR, null);
|
||||
}
|
||||
final char[] featureName = fTokens.getCharImage();
|
||||
boolean supported = CPreprocessor.getSupportedFeatures().contains(new String(featureName));
|
||||
consume(); // feature name token
|
||||
if (LA() != IToken.tRPAREN) {
|
||||
throw new EvalException(IProblem.SCANNER_MISSING_R_PAREN, null);
|
||||
}
|
||||
consume(); // closing parenthesis
|
||||
return supported ? 1 : 0;
|
||||
}
|
||||
|
||||
private int LA() {
|
||||
return fTokens.getType();
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public class MacroExpander {
|
|||
public TokenList expand(ITokenSequence lexer, final int ppOptions,
|
||||
PreprocessorMacro macro, Token identifier, boolean completionMode,
|
||||
ScannerContext scannerContext) throws OffsetLimitReachedException {
|
||||
final boolean protectDefined= (ppOptions & CPreprocessor.PROTECT_DEFINED) != 0;
|
||||
final boolean protectIntrinsics= (ppOptions & CPreprocessor.PROTECT_INTRINSICS) != 0;
|
||||
if ((ppOptions & CPreprocessor.REPORT_SIGNIFICANT_MACROS) != 0) {
|
||||
fReportMacros= scannerContext;
|
||||
fReportUndefined= (ppOptions & CPreprocessor.IGNORE_UNDEFINED_SIGNIFICANT_MACROS) == 0;
|
||||
|
@ -184,7 +184,7 @@ public class MacroExpander {
|
|||
|
||||
input.prepend(firstExpansion);
|
||||
|
||||
result= expandAll(input, forbidden, protectDefined, null);
|
||||
result= expandAll(input, forbidden, protectIntrinsics, null);
|
||||
} catch (CompletionInMacroExpansionException e) {
|
||||
// For content assist in macro expansions, we return the list of tokens of the
|
||||
// parameter at the current cursor position and hope that they make sense if
|
||||
|
@ -351,7 +351,7 @@ public class MacroExpander {
|
|||
}
|
||||
|
||||
private TokenList expandAll(TokenSource input, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden,
|
||||
boolean protectDefinedConstructs, MacroExpansionTracker tracker) throws OffsetLimitReachedException {
|
||||
boolean protectIntrinsics, MacroExpansionTracker tracker) throws OffsetLimitReachedException {
|
||||
final TokenList result= new TokenList();
|
||||
boolean protect= false;
|
||||
Token l= null;
|
||||
|
@ -366,10 +366,14 @@ public class MacroExpander {
|
|||
PreprocessorMacro macro= fDictionary.get(image);
|
||||
if (protect || (tracker != null && tracker.isDone())) {
|
||||
result.append(t);
|
||||
} else if (protectDefinedConstructs && Arrays.equals(image, Keywords.cDEFINED)) {
|
||||
} else if (protectIntrinsics && Arrays.equals(image, Keywords.cDEFINED)) {
|
||||
t.setType(CPreprocessor.tDEFINED);
|
||||
result.append(t);
|
||||
protect= true;
|
||||
} else if (protectIntrinsics && Arrays.equals(image, Keywords.c__HAS_FEATURE)) {
|
||||
t.setType(CPreprocessor.t__HAS_FEATURE);
|
||||
result.append(t);
|
||||
protect= true;
|
||||
} else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) {
|
||||
// Tricky: Don't mark function-style macros if you don't find the left parenthesis
|
||||
if (fReportMacros != null) {
|
||||
|
|
Loading…
Add table
Reference in a new issue