Internals: update clang attributes check report conditions (#3997)
This commit is contained in:
parent
8a5804fc3a
commit
0130c2bceb
|
|
@ -2982,7 +2982,7 @@ VerilatedModule::~VerilatedModule() {
|
||||||
// VerilatedVar:: Methods
|
// VerilatedVar:: Methods
|
||||||
|
|
||||||
// cppcheck-suppress unusedFunction // Used by applications
|
// cppcheck-suppress unusedFunction // Used by applications
|
||||||
uint32_t VerilatedVarProps::entSize() const {
|
uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
||||||
uint32_t size = 1;
|
uint32_t size = 1;
|
||||||
switch (vltype()) {
|
switch (vltype()) {
|
||||||
case VLVT_PTR: size = sizeof(void*); break;
|
case VLVT_PTR: size = sizeof(void*); break;
|
||||||
|
|
@ -3002,7 +3002,7 @@ size_t VerilatedVarProps::totalSize() const {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
|
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
|
||||||
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
|
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
|
||||||
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
|
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
|
||||||
const int indxAdj = indx - low(dim);
|
const int indxAdj = indx - low(dim);
|
||||||
|
|
@ -3121,7 +3121,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* VerilatedScope::exportFindError(int funcnum) const {
|
void* VerilatedScope::exportFindError(int funcnum) const VL_MT_SAFE {
|
||||||
// Slowpath - Called only when find has failed
|
// Slowpath - Called only when find has failed
|
||||||
const std::string msg
|
const std::string msg
|
||||||
= (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum)
|
= (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum)
|
||||||
|
|
|
||||||
|
|
@ -647,7 +647,7 @@ public: // But internals only - called from VerilatedModule's
|
||||||
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
|
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
|
||||||
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
|
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
|
||||||
void scopeDump() const;
|
void scopeDump() const;
|
||||||
void* exportFindError(int funcnum) const;
|
void* exportFindError(int funcnum) const VL_MT_SAFE;
|
||||||
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
||||||
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
||||||
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
|
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
|
||||||
|
|
|
||||||
|
|
@ -137,35 +137,35 @@ public:
|
||||||
~VerilatedVarProps() = default;
|
~VerilatedVarProps() = default;
|
||||||
// METHODS
|
// METHODS
|
||||||
bool magicOk() const { return m_magic == MAGIC; }
|
bool magicOk() const { return m_magic == MAGIC; }
|
||||||
VerilatedVarType vltype() const { return m_vltype; }
|
VerilatedVarType vltype() const VL_MT_SAFE { return m_vltype; }
|
||||||
VerilatedVarFlags vldir() const {
|
VerilatedVarFlags vldir() const {
|
||||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
||||||
}
|
}
|
||||||
uint32_t entSize() const;
|
uint32_t entSize() const VL_MT_SAFE;
|
||||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||||
// DPI compatible C standard layout
|
// DPI compatible C standard layout
|
||||||
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
||||||
int udims() const { return m_udims; }
|
int udims() const VL_MT_SAFE { return m_udims; }
|
||||||
int dims() const { return m_pdims + m_udims; }
|
int dims() const { return m_pdims + m_udims; }
|
||||||
const VerilatedRange& packed() const { return m_packed; }
|
const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; }
|
||||||
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
||||||
// DPI accessors
|
// DPI accessors
|
||||||
int left(int dim) const {
|
int left(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.left()
|
return dim == 0 ? m_packed.left()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int right(int dim) const {
|
int right(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.right()
|
return dim == 0 ? m_packed.right()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int low(int dim) const {
|
int low(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.low()
|
return dim == 0 ? m_packed.low()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int high(int dim) const {
|
int high(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.high()
|
return dim == 0 ? m_packed.high()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
||||||
: 0;
|
: 0;
|
||||||
|
|
@ -175,7 +175,7 @@ public:
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int elements(int dim) const {
|
int elements(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.elements()
|
return dim == 0 ? m_packed.elements()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
|
||||||
: 0;
|
: 0;
|
||||||
|
|
@ -183,7 +183,7 @@ public:
|
||||||
// Total size in bytes (note DPI limited to 4GB)
|
// Total size in bytes (note DPI limited to 4GB)
|
||||||
size_t totalSize() const;
|
size_t totalSize() const;
|
||||||
// Adjust a data pointer to access a given array element, NULL if something goes bad
|
// Adjust a data pointer to access a given array element, NULL if something goes bad
|
||||||
void* datapAdjustIndex(void* datap, int dim, int indx) const;
|
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE;
|
||||||
};
|
};
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
@ -203,22 +203,22 @@ public:
|
||||||
, m_datap{const_cast<void*>(datap)} {}
|
, m_datap{const_cast<void*>(datap)} {}
|
||||||
~VerilatedDpiOpenVar() = default;
|
~VerilatedDpiOpenVar() = default;
|
||||||
// METHODS
|
// METHODS
|
||||||
void* datap() const { return m_datap; }
|
void* datap() const VL_MT_SAFE { return m_datap; }
|
||||||
// METHODS - from VerilatedVarProps
|
// METHODS - from VerilatedVarProps
|
||||||
bool magicOk() const { return m_propsp->magicOk(); }
|
bool magicOk() const { return m_propsp->magicOk(); }
|
||||||
VerilatedVarType vltype() const { return m_propsp->vltype(); }
|
VerilatedVarType vltype() const { return m_propsp->vltype(); }
|
||||||
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
|
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
|
||||||
const VerilatedRange& packed() const { return m_propsp->packed(); }
|
const VerilatedRange& packed() const { return m_propsp->packed(); }
|
||||||
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
|
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
|
||||||
int udims() const { return m_propsp->udims(); }
|
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
|
||||||
int left(int dim) const { return m_propsp->left(dim); }
|
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
|
||||||
int right(int dim) const { return m_propsp->right(dim); }
|
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
|
||||||
int low(int dim) const { return m_propsp->low(dim); }
|
int low(int dim) const { return m_propsp->low(dim); }
|
||||||
int high(int dim) const { return m_propsp->high(dim); }
|
int high(int dim) const { return m_propsp->high(dim); }
|
||||||
int increment(int dim) const { return m_propsp->increment(dim); }
|
int increment(int dim) const { return m_propsp->increment(dim); }
|
||||||
int elements(int dim) const { return m_propsp->elements(dim); }
|
int elements(int dim) const { return m_propsp->elements(dim); }
|
||||||
size_t totalSize() const { return m_propsp->totalSize(); }
|
size_t totalSize() const { return m_propsp->totalSize(); }
|
||||||
void* datapAdjustIndex(void* datap, int dim, int indx) const {
|
void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE {
|
||||||
return m_propsp->datapAdjustIndex(datap, dim, indx);
|
return m_propsp->datapAdjustIndex(datap, dim, indx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,7 @@ class CallAnnotationsValidator:
|
||||||
self._call_location: Optional[FunctionInfo] = None
|
self._call_location: Optional[FunctionInfo] = None
|
||||||
self._caller: Optional[FunctionInfo] = None
|
self._caller: Optional[FunctionInfo] = None
|
||||||
self._level: int = 0
|
self._level: int = 0
|
||||||
|
self._constructor_context: int = 0
|
||||||
|
|
||||||
def compile_and_analyze_file(self, source_file: str,
|
def compile_and_analyze_file(self, source_file: str,
|
||||||
compiler_args: list[str],
|
compiler_args: list[str],
|
||||||
|
|
@ -300,6 +301,67 @@ class CallAnnotationsValidator:
|
||||||
annotations = VlAnnotations.from_nodes_list(children)
|
annotations = VlAnnotations.from_nodes_list(children)
|
||||||
return (True, refd, annotations, children)
|
return (True, refd, annotations, children)
|
||||||
|
|
||||||
|
def check_mt_safe_call(self, node: clang.cindex.Cursor,
|
||||||
|
refd: clang.cindex.Cursor,
|
||||||
|
annotations: VlAnnotations):
|
||||||
|
is_mt_safe = False
|
||||||
|
|
||||||
|
if annotations.is_mt_safe_call():
|
||||||
|
is_mt_safe = True
|
||||||
|
elif not annotations.is_mt_unsafe_call():
|
||||||
|
# Check whether the object the method is called on is mt-safe
|
||||||
|
def find_object_ref(node):
|
||||||
|
try:
|
||||||
|
node = next(node.get_children())
|
||||||
|
if node.kind == CursorKind.DECL_REF_EXPR:
|
||||||
|
# Operator on an argument or local object
|
||||||
|
return node
|
||||||
|
if node.kind != CursorKind.MEMBER_REF_EXPR:
|
||||||
|
return None
|
||||||
|
if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL:
|
||||||
|
# Operator on a member object
|
||||||
|
return node
|
||||||
|
node = next(node.get_children())
|
||||||
|
if node.kind == CursorKind.UNEXPOSED_EXPR:
|
||||||
|
node = next(node.get_children())
|
||||||
|
return node
|
||||||
|
except StopIteration:
|
||||||
|
return None
|
||||||
|
|
||||||
|
refn = find_object_ref(node)
|
||||||
|
if self._constructor_context and not refn:
|
||||||
|
# we are in constructor and no object reference means
|
||||||
|
# we are calling local method. It is MT safe
|
||||||
|
# only if this method is also only calling local methods or
|
||||||
|
# MT-safe methods
|
||||||
|
self.iterate_children(refd.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
|
is_mt_safe = True
|
||||||
|
# class/struct member
|
||||||
|
elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
||||||
|
refn = refn.referenced
|
||||||
|
refna = VlAnnotations.from_nodes_list(refn.get_children())
|
||||||
|
if refna.guarded or self._constructor_context:
|
||||||
|
is_mt_safe = True
|
||||||
|
# variable
|
||||||
|
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
||||||
|
# This is probably a local or an argument.
|
||||||
|
# Calling methods on local pointers or references is MT-safe,
|
||||||
|
# but on argument pointers or references is not.
|
||||||
|
if "*" not in refn.type.spelling and "&" not in refn.type.spelling:
|
||||||
|
is_mt_safe = True
|
||||||
|
# local variable
|
||||||
|
if refn.referenced.kind == CursorKind.VAR_DECL:
|
||||||
|
is_mt_safe = True
|
||||||
|
elif refn and refn.kind == CursorKind.CALL_EXPR:
|
||||||
|
if self._constructor_context:
|
||||||
|
# call to local function from constructor context
|
||||||
|
# safe if this function also calling local methods or
|
||||||
|
# MT-safe methods
|
||||||
|
self.dispatch_call_node(refn)
|
||||||
|
is_mt_safe = True
|
||||||
|
return is_mt_safe
|
||||||
|
|
||||||
# Call handling
|
# Call handling
|
||||||
|
|
||||||
def process_method_call(self, node: clang.cindex.Cursor,
|
def process_method_call(self, node: clang.cindex.Cursor,
|
||||||
|
|
@ -310,43 +372,7 @@ class CallAnnotationsValidator:
|
||||||
|
|
||||||
# MT-safe context
|
# MT-safe context
|
||||||
if ctx.is_mt_safe_context():
|
if ctx.is_mt_safe_context():
|
||||||
is_mt_safe = False
|
if not self.check_mt_safe_call(node, refd, annotations):
|
||||||
|
|
||||||
if annotations.is_mt_safe_call():
|
|
||||||
is_mt_safe = True
|
|
||||||
elif not annotations.is_mt_unsafe_call():
|
|
||||||
# Check whether the object the method is called on is mt-safe
|
|
||||||
def find_object_ref(node):
|
|
||||||
try:
|
|
||||||
node = next(node.get_children())
|
|
||||||
if node.kind == CursorKind.DECL_REF_EXPR:
|
|
||||||
# Operator on an argument or local object
|
|
||||||
return node
|
|
||||||
if node.kind != CursorKind.MEMBER_REF_EXPR:
|
|
||||||
return None
|
|
||||||
if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL:
|
|
||||||
# Operator on a member object
|
|
||||||
return node
|
|
||||||
node = next(node.get_children())
|
|
||||||
if node.kind == CursorKind.UNEXPOSED_EXPR:
|
|
||||||
node = next(node.get_children())
|
|
||||||
return node
|
|
||||||
except StopIteration:
|
|
||||||
return None
|
|
||||||
|
|
||||||
refn = find_object_ref(node)
|
|
||||||
# class/struct member
|
|
||||||
if refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
|
||||||
refn = refn.referenced
|
|
||||||
refna = VlAnnotations.from_nodes_list(refn.get_children())
|
|
||||||
if refna.guarded:
|
|
||||||
is_mt_safe = True
|
|
||||||
# variable
|
|
||||||
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
|
||||||
# This is probably a local or an argument. Assume it's safe.
|
|
||||||
is_mt_safe = True
|
|
||||||
|
|
||||||
if not is_mt_safe:
|
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
FunctionInfo.from_node(refd, refd, annotations),
|
||||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||||
|
|
@ -380,7 +406,13 @@ class CallAnnotationsValidator:
|
||||||
assert self._call_location
|
assert self._call_location
|
||||||
ctx = self._call_location.annotations
|
ctx = self._call_location.annotations
|
||||||
|
|
||||||
# Constructors are always OK in MT-safe context.
|
# Constructors are OK in MT-safe context
|
||||||
|
# only if they call local methods or MT-safe functions.
|
||||||
|
if ctx.is_mt_safe_context() or self._constructor_context:
|
||||||
|
self._constructor_context += 1
|
||||||
|
self.iterate_children(refd.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
|
self._constructor_context -= 1
|
||||||
|
|
||||||
# pure context
|
# pure context
|
||||||
if ctx.is_pure_context():
|
if ctx.is_pure_context():
|
||||||
|
|
@ -412,6 +444,8 @@ class CallAnnotationsValidator:
|
||||||
or refd.kind == CursorKind.CXX_METHOD
|
or refd.kind == CursorKind.CXX_METHOD
|
||||||
and refd.is_static_method()):
|
and refd.is_static_method()):
|
||||||
self.process_function_call(refd, annotations)
|
self.process_function_call(refd, annotations)
|
||||||
|
self.iterate_children(node.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
return
|
return
|
||||||
# Function pointer
|
# Function pointer
|
||||||
if refd.kind in [
|
if refd.kind in [
|
||||||
|
|
@ -419,18 +453,26 @@ class CallAnnotationsValidator:
|
||||||
CursorKind.PARM_DECL
|
CursorKind.PARM_DECL
|
||||||
]:
|
]:
|
||||||
self.process_function_call(refd, annotations)
|
self.process_function_call(refd, annotations)
|
||||||
|
self.iterate_children(node.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
return
|
return
|
||||||
# Non-static class methods
|
# Non-static class methods
|
||||||
if refd.kind == CursorKind.CXX_METHOD:
|
if refd.kind == CursorKind.CXX_METHOD:
|
||||||
self.process_method_call(node, refd, annotations)
|
self.process_method_call(node, refd, annotations)
|
||||||
|
self.iterate_children(node.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
return
|
return
|
||||||
# Conversion method (e.g. `operator int()`)
|
# Conversion method (e.g. `operator int()`)
|
||||||
if refd.kind == CursorKind.CONVERSION_FUNCTION:
|
if refd.kind == CursorKind.CONVERSION_FUNCTION:
|
||||||
self.process_method_call(node, refd, annotations)
|
self.process_method_call(node, refd, annotations)
|
||||||
|
self.iterate_children(node.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
return
|
return
|
||||||
# Constructors
|
# Constructors
|
||||||
if refd.kind == CursorKind.CONSTRUCTOR:
|
if refd.kind == CursorKind.CONSTRUCTOR:
|
||||||
self.process_constructor_call(refd, annotations)
|
self.process_constructor_call(refd, annotations)
|
||||||
|
self.iterate_children(node.get_children(),
|
||||||
|
self.dispatch_node_inside_definition)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Ignore other callables
|
# Ignore other callables
|
||||||
|
|
@ -461,9 +503,6 @@ class CallAnnotationsValidator:
|
||||||
|
|
||||||
assert refd is not None
|
assert refd is not None
|
||||||
|
|
||||||
prev_caller = self._caller
|
|
||||||
prev_call_location = self._call_location
|
|
||||||
|
|
||||||
def_annotations = VlAnnotations.from_nodes_list(node_children)
|
def_annotations = VlAnnotations.from_nodes_list(node_children)
|
||||||
|
|
||||||
if not (def_annotations.is_empty() or def_annotations == annotations):
|
if not (def_annotations.is_empty() or def_annotations == annotations):
|
||||||
|
|
@ -485,8 +524,7 @@ class CallAnnotationsValidator:
|
||||||
self.iterate_children(node_children,
|
self.iterate_children(node_children,
|
||||||
self.dispatch_node_inside_definition)
|
self.dispatch_node_inside_definition)
|
||||||
|
|
||||||
self._call_location = prev_call_location
|
self._call_location = None
|
||||||
self._caller = prev_caller
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -704,8 +742,7 @@ class TopDownSummaryPrinter():
|
||||||
info: FunctionInfo
|
info: FunctionInfo
|
||||||
calees: set[FunctionInfo]
|
calees: set[FunctionInfo]
|
||||||
mismatch: Optional[FunctionInfo] = None
|
mismatch: Optional[FunctionInfo] = None
|
||||||
non_mt_safe_call_in_mt_safe: Optional[FunctionInfo] = None
|
reason: Optional[DiagnosticKind] = None
|
||||||
non_pure_call_in_pure: Optional[FunctionInfo] = None
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._is_first_group = True
|
self._is_first_group = True
|
||||||
|
|
@ -727,15 +764,12 @@ class TopDownSummaryPrinter():
|
||||||
if func is None:
|
if func is None:
|
||||||
func = TopDownSummaryPrinter.FunctionCallees(diag.source, set())
|
func = TopDownSummaryPrinter.FunctionCallees(diag.source, set())
|
||||||
self._funcs[usr] = func
|
self._funcs[usr] = func
|
||||||
|
func.reason = diag.kind
|
||||||
if diag.kind == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
|
if diag.kind == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
|
||||||
func.mismatch = diag.target
|
func.mismatch = diag.target
|
||||||
else:
|
else:
|
||||||
func.calees.add(diag.target)
|
func.calees.add(diag.target)
|
||||||
self._unsafe_in_safe.add(diag.target.usr)
|
self._unsafe_in_safe.add(diag.target.usr)
|
||||||
if diag.kind == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX:
|
|
||||||
func.non_mt_safe_call_in_mt_safe = diag.target
|
|
||||||
elif diag.kind == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
|
|
||||||
func.non_pure_call_in_pure = diag.target
|
|
||||||
|
|
||||||
def print_summary(self, root_dir: str):
|
def print_summary(self, root_dir: str):
|
||||||
row_groups: dict[str, list[list[str]]] = {}
|
row_groups: dict[str, list[list[str]]] = {}
|
||||||
|
|
@ -748,11 +782,11 @@ class TopDownSummaryPrinter():
|
||||||
|
|
||||||
row_group = []
|
row_group = []
|
||||||
name = f"\"{func_info.name}\" "
|
name = f"\"{func_info.name}\" "
|
||||||
if func.mismatch:
|
if func.reason == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH:
|
||||||
name += "declaration does not match definition"
|
name += "declaration does not match definition"
|
||||||
elif func.non_mt_safe_call_in_mt_safe:
|
elif func.reason == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX:
|
||||||
name += "is mtsafe but calls non-mtsafe function(s)"
|
name += "is mtsafe but calls non-mtsafe function(s)"
|
||||||
elif func.non_pure_call_in_pure:
|
elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX:
|
||||||
name += "is pure but calls non-pure function(s)"
|
name += "is pure but calls non-pure function(s)"
|
||||||
else:
|
else:
|
||||||
name += "for unknown reason (please add description)"
|
name += "for unknown reason (please add description)"
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ sub check {
|
||||||
tee => 1,
|
tee => 1,
|
||||||
cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]);
|
cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]);
|
||||||
|
|
||||||
file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 14");
|
file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 27");
|
||||||
}
|
}
|
||||||
|
|
||||||
run_clang_check();
|
run_clang_check();
|
||||||
|
|
|
||||||
|
|
@ -273,4 +273,114 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void static_function() {}
|
||||||
|
|
||||||
|
class StaticClass {
|
||||||
|
public:
|
||||||
|
static void static_class_function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorCallsUnsafeLocalFunction {
|
||||||
|
public:
|
||||||
|
void unsafe_function() VL_MT_UNSAFE{};
|
||||||
|
ConstructorCallsUnsafeLocalFunction() { unsafe_function(); }
|
||||||
|
};
|
||||||
|
class ConstructorCallsStaticFunctionNoAnnotation {
|
||||||
|
public:
|
||||||
|
ConstructorCallsStaticFunctionNoAnnotation() { static_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorCallsLocalFunction {
|
||||||
|
public:
|
||||||
|
void local_function() {}
|
||||||
|
ConstructorCallsLocalFunction() { local_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorCallsLocalFunctionCallsGlobal {
|
||||||
|
public:
|
||||||
|
void local_function() { static_function(); }
|
||||||
|
ConstructorCallsLocalFunctionCallsGlobal() { local_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SafeFunction {
|
||||||
|
public:
|
||||||
|
void safe_function() VL_MT_SAFE {}
|
||||||
|
};
|
||||||
|
class UnsafeFunction {
|
||||||
|
public:
|
||||||
|
void unsafe_function() VL_MT_UNSAFE {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorWithPointer {
|
||||||
|
public:
|
||||||
|
ConstructorWithPointer(SafeFunction* p) { p->safe_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorWithReference {
|
||||||
|
public:
|
||||||
|
ConstructorWithReference(SafeFunction& p) { p.safe_function(); }
|
||||||
|
};
|
||||||
|
class ConstructorWithUnsafePointer {
|
||||||
|
public:
|
||||||
|
ConstructorWithUnsafePointer(UnsafeFunction* p) { p->unsafe_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorWithUnsafeReference {
|
||||||
|
public:
|
||||||
|
ConstructorWithUnsafeReference(UnsafeFunction& p) { p.unsafe_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorCallsLocalCallsGlobal {
|
||||||
|
void local_function2() { static_function(); }
|
||||||
|
void local_function() { local_function2(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConstructorCallsLocalCallsGlobal() { local_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstructorCallsLocalCallsClassGlobal {
|
||||||
|
void local_function2() { StaticClass::static_class_function(); }
|
||||||
|
void local_function() { local_function2(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConstructorCallsLocalCallsClassGlobal() { local_function(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestClassConstructor {
|
||||||
|
void safe_function_unsafe_constructor_bad() VL_MT_SAFE {
|
||||||
|
ConstructorCallsUnsafeLocalFunction f{};
|
||||||
|
};
|
||||||
|
void safe_function_static_constructor_bad() VL_MT_SAFE {
|
||||||
|
ConstructorCallsStaticFunctionNoAnnotation f{};
|
||||||
|
};
|
||||||
|
void safe_function_local_function_global_bad() VL_MT_SAFE {
|
||||||
|
ConstructorCallsLocalFunctionCallsGlobal f{};
|
||||||
|
}
|
||||||
|
void safe_function_local_function_constructor_good() VL_MT_SAFE {
|
||||||
|
ConstructorCallsLocalFunction f{};
|
||||||
|
}
|
||||||
|
void safe_function_calls_constructor_with_pointer_good() VL_MT_SAFE {
|
||||||
|
SafeFunction* i = new SafeFunction{};
|
||||||
|
ConstructorWithPointer f{i};
|
||||||
|
}
|
||||||
|
void safe_function_calls_constructor_with_reference_good() VL_MT_SAFE {
|
||||||
|
SafeFunction i;
|
||||||
|
ConstructorWithReference f{i};
|
||||||
|
}
|
||||||
|
void safe_function_calls_constructor_with_unsafepointer_bad() VL_MT_SAFE {
|
||||||
|
UnsafeFunction* i = new UnsafeFunction{};
|
||||||
|
ConstructorWithUnsafePointer f{i};
|
||||||
|
}
|
||||||
|
void safe_function_calls_constructor_with_unsafereference_bad() VL_MT_SAFE {
|
||||||
|
UnsafeFunction i;
|
||||||
|
ConstructorWithUnsafeReference f{i};
|
||||||
|
}
|
||||||
|
void safe_function_calls_constructor_local_calls_global_bad() VL_MT_SAFE {
|
||||||
|
ConstructorCallsLocalCallsGlobal f{};
|
||||||
|
}
|
||||||
|
void safe_function_calls_constructor_local_calls_class_global_bad() VL_MT_SAFE {
|
||||||
|
ConstructorCallsLocalCallsClassGlobal f{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // T_DIST_ATTRIBUTES_BAD_H_
|
#endif // T_DIST_ATTRIBUTES_BAD_H_
|
||||||
|
|
|
||||||
|
|
@ -724,6 +724,34 @@ t/t_dist_attributes_bad.cpp:75: [release] TestClass
|
||||||
t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) [declaration]
|
t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) [declaration]
|
||||||
t/t_dist_attributes_bad.cpp:75: [requires] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &)
|
t/t_dist_attributes_bad.cpp:75: [requires] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &)
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:381: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad()
|
||||||
|
t/t_dist_attributes_bad.h:280: [] StaticClass::static_class_function()
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:378: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad()
|
||||||
|
t/t_dist_attributes_bad.h:276: [] static_function()
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:370: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad()
|
||||||
|
t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function()
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:374: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad()
|
||||||
|
t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function()
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_local_function_global_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:356: [mt_safe] TestClassConstructor::safe_function_local_function_global_bad()
|
||||||
|
t/t_dist_attributes_bad.h:276: [] static_function()
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_static_constructor_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:353: [mt_safe] TestClassConstructor::safe_function_static_constructor_bad()
|
||||||
|
t/t_dist_attributes_bad.h:276: [] static_function()
|
||||||
|
|
||||||
|
%Error: "TestClassConstructor::safe_function_unsafe_constructor_bad()" is mtsafe but calls non-mtsafe function(s)
|
||||||
|
t/t_dist_attributes_bad.h:350: [mt_safe] TestClassConstructor::safe_function_unsafe_constructor_bad()
|
||||||
|
t/t_dist_attributes_bad.h:285: [mt_unsafe] ConstructorCallsUnsafeLocalFunction::unsafe_function()
|
||||||
|
|
||||||
%Error: "ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s)
|
%Error: "ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s)
|
||||||
t/t_dist_attributes_bad.cpp:53: [mt_safe] ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)
|
t/t_dist_attributes_bad.cpp:53: [mt_safe] ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)
|
||||||
t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &)
|
t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &)
|
||||||
|
|
@ -1157,4 +1185,4 @@ t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_
|
||||||
t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE(VerilatedMutex &)
|
t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE(VerilatedMutex &)
|
||||||
t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE_SHARED(VerilatedMutex &)
|
t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE_SHARED(VerilatedMutex &)
|
||||||
t/t_dist_attributes_bad.cpp:60: [requires] sfc_VL_REQUIRES(VerilatedMutex &)
|
t/t_dist_attributes_bad.cpp:60: [requires] sfc_VL_REQUIRES(VerilatedMutex &)
|
||||||
Number of functions reported unsafe: 220
|
Number of functions reported unsafe: 224
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue