Skip to content

Commit

Permalink
Fix include order in CXType.cpp
Browse files Browse the repository at this point in the history
Handle template parameter-dependent bit field widths in libclang

In a class template, a bit field's width may depend on a template
parameter. In this case the width expression cannot be evaluated.

Previously clang_getFieldDeclBitWidth() would assert, or cause memory
unsafety and return an invalid result if assertions are disabled.

This adds a check for this case which returns an error code. An
additional function clang_isBitFieldDecl() is added to disambiguate
between error code meanings.

Fixes: #56644
Differential Revision: https://reviews.llvm.org/D130303
  • Loading branch information
chbaker0 authored and AaronBallman committed Mar 13, 2023
1 parent 2a84c53 commit 4d55a0b
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 4 deletions.
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Expand Up @@ -296,6 +296,11 @@ libclang
- Introduced the new function ``clang_CXXMethod_isExplicit``,
which identifies whether a constructor or conversion function cursor
was marked with the explicit identifier.
- Added check in ``clang_getFieldDeclBitWidth`` for whether a bit field
has an evaluable bit width. Fixes undefined behavior when called on a
bit field whose width depends on a template paramter.
- Added function ``clang_isBitFieldDecl`` to check if a struct/class field is a
bit field.

- Introduced the new ``CXIndex`` constructor function
``clang_createIndexWithOptions``, which allows overriding precompiled preamble
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang-c/Index.h
Expand Up @@ -3023,10 +3023,18 @@ CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C);
CINDEX_LINKAGE unsigned long long
clang_getEnumConstantDeclUnsignedValue(CXCursor C);

/**
* Returns non-zero if a field declaration has a bit width expression.
*
* If the cursor does not reference a bit field declaration 0 is returned.
*/
CINDEX_LINKAGE unsigned clang_isBitFieldDecl(CXCursor C);

/**
* Retrieve the bit width of a bit field declaration as an integer.
*
* If a cursor that is not a bit field declaration is passed in, -1 is returned.
* If the cursor does not reference a bit field, or if the bit field's width
* expression cannot be evaluated, -1 is returned.
*/
CINDEX_LINKAGE int clang_getFieldDeclBitWidth(CXCursor C);

Expand Down
19 changes: 16 additions & 3 deletions clang/tools/libclang/CXType.cpp
Expand Up @@ -10,11 +10,11 @@
//
//===--------------------------------------------------------------------===//

#include "CXType.h"
#include "CIndexer.h"
#include "CXCursor.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "CXType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
Expand Down Expand Up @@ -371,14 +371,27 @@ unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) {
return ULLONG_MAX;
}

unsigned clang_isBitFieldDecl(CXCursor C) {
using namespace cxcursor;

if (clang_isDeclaration(C.kind)) {
const Decl *D = getCursorDecl(C);

if (const auto *FD = dyn_cast_or_null<FieldDecl>(D))
return FD->isBitField();
}

return 0;
}

int clang_getFieldDeclBitWidth(CXCursor C) {
using namespace cxcursor;

if (clang_isDeclaration(C.kind)) {
const Decl *D = getCursorDecl(C);

if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) {
if (FD->isBitField())
if (const auto *FD = dyn_cast_or_null<FieldDecl>(D)) {
if (FD->isBitField() && !FD->getBitWidth()->isValueDependent())
return FD->getBitWidthValue(getCursorContext(C));
}
}
Expand Down
1 change: 1 addition & 0 deletions clang/tools/libclang/libclang.map
Expand Up @@ -422,6 +422,7 @@ LLVM_17 {
global:
clang_CXXMethod_isExplicit;
clang_createIndexWithOptions;
clang_isBitFieldDecl;
};

# Example of how to add a new symbol version entry. If you do add a new symbol
Expand Down

0 comments on commit 4d55a0b

Please sign in to comment.