1
0
Fork 0
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:
Nathan Ridge 2015-07-03 18:27:43 -04:00 committed by Gerrit Code Review @ Eclipse.org
parent aea96f8c1b
commit a9a454f256
6 changed files with 169 additions and 10 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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) {