1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-03 14:25:37 +02:00

Bug 512932 - Improve type checking of GCC builtins

Specifically, this patch:

  - Adds support for a new builtin, __builtin_assume_aligned.

  - Models __builtin_constant_p as a function instead of a macro.
    This inhibits constexpr evaluation, but allows for correct
    type-checking.

  - Diagnoses misuses of known builtins, instead of ingoring them like
    unknown builtins.

Change-Id: Ie5a26f2010dc5b19e6f32a8c6a1237fe88da393e
This commit is contained in:
Nathan Ridge 2017-05-02 03:40:00 -04:00
parent ca29390671
commit 60503efc58
14 changed files with 126 additions and 29 deletions

View file

@ -41,7 +41,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
@ -148,8 +148,7 @@ public class ProblemBindingChecker extends AbstractIndexAstChecker {
if (id != IProblemBinding.SEMANTIC_NAME_NOT_FOUND) {
return PROCESS_CONTINUE;
}
if (problemBinding.getID() == IProblemBinding.SEMANTIC_NAME_NOT_FOUND &&
CharArrayUtils.startsWith(problemBinding.getNameCharArray(), "__builtin_")) { //$NON-NLS-1$
if (SemanticQueries.isUnknownBuiltin(problemBinding, name)) {
return PROCESS_CONTINUE; // Ignore an unknown built-in.
}
if (isFunctionCall(name, parentNode)) {

View file

@ -109,4 +109,12 @@ public class ProblemBindingCheckerTest extends CheckerTestCase {
loadCodeAndRun(getAboveComment());
checkErrorLine(3, ProblemBindingChecker.ERR_ID_InvalidArguments);
}
// void foo(unsigned i) {
// __builtin_assume_aligned(i, 4);
// }
public void testMisuseOfKnownBuiltin_512932() throws Exception {
loadCodeAndRun(getAboveComment());
checkErrorLine(2, ProblemBindingChecker.ERR_ID_InvalidArguments);
}
}

View file

@ -11247,6 +11247,36 @@ public class AST2CPPTests extends AST2TestBase {
assertSameType((ITypedef) helper.assertNonProblem("ulong_type"), CPPBasicType.UNSIGNED_LONG);
assertSameType((ITypedef) helper.assertNonProblem("loong_type"), CPPBasicType.LONG);
}
// void ptrFunc(void*);
// void intFunc(int);
// void foo(int* pi, unsigned i) {
// ptrFunc(__builtin_assume_aligned(pi, 4));
// intFunc(__builtin_constant_p(i));
// intFunc(__builtin_expect(i, 0));
// ptrFunc(__builtin_return_address(4));
// }
public void testGCCBuiltins_512932a() throws Exception {
parseAndCheckBindings(getAboveComment(), CPP, true);
}
// void ptrFunc(void*);
// void intFunc(int);
// void foo(int* pi, unsigned i) {
// ptrFunc(__builtin_assume_aligned(i, 4));
// ptrFunc(__builtin_constant_p(i));
// ptrFunc(__builtin_constant_p(pI));
// intFunc(__builtin_expect(pI, (int*)0));
// ptrFunc(__builtin_expect(i, 0));
// }
public void testGCCBuiltins_512932b() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertProblem("__builtin_assume_aligned", "__builtin_assume_aligned");
helper.assertProblem("ptrFunc(__builtin_constant_p(i", "ptrFunc");
helper.assertProblem("ptrFunc(__builtin_constant_p(pI", "ptrFunc");
helper.assertProblem("__builtin_expect(pI", "__builtin_expect");
helper.assertProblem("ptrFunc(__builtin_expect", "ptrFunc");
}
// namespace A {
// int a;

View file

@ -18,7 +18,11 @@ import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPInheritance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPInheritance.FinalOverriderMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
@ -108,4 +112,27 @@ public class SemanticQueries {
}
return pureVirtualMethods.toArray(new ICPPMethod[pureVirtualMethods.size()]);
}
/**
* Returns whether a problem binding represents a name resolution error due to an unknown built-in.
* Importantly, this will not return true for a misuse of a known builtin, which we want to diagnose.
* @param binding The problem binding to test.
* @param node Any node in the AST. Used to access the AST root.
* @since 6.3
*/
public static boolean isUnknownBuiltin(IProblemBinding binding, IASTNode node) {
char[] name = binding.getNameCharArray();
boolean isBuiltin = binding.getID() == IProblemBinding.SEMANTIC_NAME_NOT_FOUND &&
CharArrayUtils.startsWith(name, "__builtin_"); //$NON-NLS-1$
if (isBuiltin) {
if (node != null) {
IASTTranslationUnit tu = node.getTranslationUnit();
if (tu instanceof ASTTranslationUnit) {
return !((ASTTranslationUnit) tu).isKnownBuiltin(name);
}
}
return true;
}
return false;
}
}

View file

@ -46,7 +46,6 @@ public abstract class GNUScannerExtensionConfiguration extends AbstractScannerEx
addMacro("__thread", "");
addMacro("__builtin_va_arg(ap,type)", "*(typeof(type) *)ap");
addMacro("__builtin_constant_p(exp)", "0");
addMacro("__builtin_types_compatible_p(x,y)", "__builtin_types_compatible_p(sizeof(x),sizeof(y))");
addMacro("__offsetof__(x)", "(x)");

View file

@ -35,4 +35,10 @@ public interface IBuiltinBindingsProvider {
*/
public IBinding[] getBuiltinBindings(IScope scope);
/**
* Returns whether the given name names a known builtin.
*
* @noreference This method is not intended to be referenced by clients.
*/
public boolean isKnownBuiltin(char[] builtinName);
}

View file

@ -40,6 +40,7 @@ import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileSet;
@ -86,6 +87,7 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat
private final Semaphore fSemaphore= new Semaphore(1);
private boolean fBasedOnIncompleteIndex;
private boolean fNodesOmitted;
private IBuiltinBindingsProvider fBuiltinBindingsProvider;
@Override
public final IASTTranslationUnit getTranslationUnit() {
@ -550,4 +552,23 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat
* process it now. Has no effect if ambiguity resolution is not in progress.
*/
public void resolvePendingAmbiguities(IASTNode node) {}
public void setupBuiltinBindings(IBuiltinBindingsProvider builtinBindingsProvider) {
IScope tuScope = getScope();
IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope);
for (IBinding binding : bindings) {
ASTInternal.addBinding(tuScope, binding);
}
// Save the builtin bindings provider for later use by isKnownBuiltin().
fBuiltinBindingsProvider = builtinBindingsProvider;
}
public boolean isKnownBuiltin(char[] builtinName) {
if (fBuiltinBindingsProvider != null) {
return fBuiltinBindingsProvider.isKnownBuiltin(builtinName);
}
return false;
}
}

View file

@ -30,6 +30,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.dom.parser.IBuiltinBindingsProvider;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArraySet;
import org.eclipse.cdt.internal.core.dom.parser.c.CArrayType;
import org.eclipse.cdt.internal.core.dom.parser.c.CBasicType;
import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinParameter;
@ -71,6 +72,8 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
private Map<String, IType> fTypeMap;
private List<IBinding> fBindingList;
private CharArraySet fKnownBuiltins = new CharArraySet(50);
public GCCBuiltinSymbolProvider(ParserLanguage lang, boolean supportGnuSymbols) {
fCpp= lang == ParserLanguage.CPP;
@ -94,6 +97,9 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
}
fBindings= fBindingList.toArray(new IBinding[fBindingList.size()]);
for (IBinding binding : fBindings) {
fKnownBuiltins.put(binding.getNameCharArray());
}
fTypeMap= null;
fBindingList= null;
}
@ -115,13 +121,13 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("void", "__builtin_va_end", "va_list");
function("void", "__builtin_va_copy", "va_list", "va_list");
// GCC 4.6.0, Section 6.48
// Return Address (https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html)
function("void*", "__builtin_return_address", "unsigned int");
function("void*", "__builtin_extract_return_address", "void*");
function("void*", "__builtin_frob_return_address", "void*");
function("void*", "__builtin_frame_address", "unsigned int");
// GCC 4.6.0, Section 6.51
// __sync Builtins (https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html)
String[] types= {"int", "long", "long long", "unsigned int", "unsigned long", "unsigned long long"};
for (String type : types) {
// Manual does not mention volatile, however functions can be used for ptr to volatile
@ -145,7 +151,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
}
function("void", "__sync_synchronize");
// GCC 4.8, Section 6.52
// __atomic Builtins (https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html)
for (String type : types) {
// Manual does not mention volatile, however functions can be used for ptr to volatile
String typePtr= "volatile " + type + "*";
@ -177,7 +183,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("bool", "__atomic_always_lock_free", "size_t", "void*");
function("bool", "__atomic_is_lock_free", "size_t", "void*");
// GCC 4.8, Section 6.55 (incomplete)
// Other Builtins (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) [incomplete]
function("void", "__builtin_abort");
function("int", "__builtin_abs", "int");
function("double", "__builtin_acos", "double");
@ -192,6 +198,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("double", "__builtin_asinh", "double");
function("float", "__builtin_asinhf", "float");
function("long double", "__builtin_asinhl", "long double");
function("void*", "__builtin_assume_aligned", "const void*", "size_t", "...");
function("double", "__builtin_atan", "double");
function("float", "__builtin_atanf", "float");
function("long double", "__builtin_atanl", "long double");
@ -218,6 +225,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("complex double", "__builtin_conj", "complex double");
function("complex float", "__builtin_conjf", "complex float");
function("complex long double", "__builtin_conjl", "complex long double");
function("int", "__builtin_constant_p", "...");
function("double", "__builtin_copysign", "double", "double");
function("float", "__builtin_copysignf", "float", "float");
function("long double", "__builtin_copysignl", "long double", "long double");
@ -596,4 +604,9 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
}
return t;
}
@Override
public boolean isKnownBuiltin(char[] builtinName) {
return fKnownBuiltins.containsKey(builtinName);
}
}

View file

@ -65,8 +65,6 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.c.ICASTArrayDesignator;
import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier;
@ -95,9 +93,9 @@ import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.CollectionUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.BacktrackException;
import org.eclipse.cdt.internal.core.dom.parser.DeclarationOptions;
@ -455,11 +453,8 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
// add built-in names to the scope
if (builtinBindingsProvider != null) {
IScope tuScope = translationUnit.getScope();
IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope);
for (IBinding binding : bindings) {
ASTInternal.addBinding(tuScope, binding);
if (translationUnit instanceof ASTTranslationUnit) {
((ASTTranslationUnit) translationUnit).setupBuiltinBindings(builtinBindingsProvider);
}
}
}

View file

@ -70,8 +70,6 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAlignmentSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument;
@ -164,9 +162,9 @@ import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.CollectionUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.BacktrackException;
import org.eclipse.cdt.internal.core.dom.parser.DeclarationOptions;
@ -4966,11 +4964,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// Add built-in names to the scope.
if (builtinBindingsProvider != null) {
IScope tuScope = translationUnit.getScope();
IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope);
for (IBinding binding : bindings) {
ASTInternal.addBinding(tuScope, binding);
if (translationUnit instanceof ASTTranslationUnit) {
((ASTTranslationUnit) translationUnit).setupBuiltinBindings(builtinBindingsProvider);
}
}
}

View file

@ -653,4 +653,11 @@ public class SemanticHighlightingTest extends TestCase {
public void testQualifiedName_511331() throws Exception {
makeAssertions();
}
// void foo(unsigned i) { //$functionDeclaration,parameterVariable
// __builtin_assume_aligned(i, 4); //$problem,parameterVariable
// }
public void testMisuseOfKnownBuiltin_512932() throws Exception {
makeAssertions();
}
}

View file

@ -37,7 +37,6 @@ public class CompletionTest_MacroRef_NoPrefix extends CompletionProposalsBaseTe
"__LINE__",
"__STDC__",
"__TIME__",
"__builtin_constant_p(exp)",
"__builtin_va_arg(ap, type)",
"__builtin_offsetof(T, m)",
"__builtin_types_compatible_p(x, y)",

View file

@ -367,7 +367,6 @@ public class CompletionTests_PlainC extends AbstractContentAssistTest {
"__STDC_VERSION__",
"__STDC__",
"__TIME__",
"__builtin_constant_p(exp)",
"__builtin_va_arg(ap, type)",
"__builtin_offsetof(T, m)",
"__builtin_types_compatible_p(x, y)",

View file

@ -74,11 +74,11 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.ui.text.ICColorConstants;
@ -1477,8 +1477,7 @@ public class SemanticHighlightings {
IBinding binding= token.getBinding();
if (binding instanceof IProblemBinding) {
IProblemBinding problemBinding = (IProblemBinding) binding;
if (problemBinding.getID() == IProblemBinding.SEMANTIC_NAME_NOT_FOUND &&
CharArrayUtils.startsWith(problemBinding.getNameCharArray(), "__builtin_")) { //$NON-NLS-1$
if (SemanticQueries.isUnknownBuiltin(problemBinding, node)) {
return false; // Ignore an unknown built-in.
}
return true;