Index: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
index 6603d6e6b804d31dc32ff4864621a53058fe0c1b..1c74e05056b5db448fee6041d9cab7384f189876 100644 |
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
@@ -56,6 +56,9 @@ const char kRefPtrToGCManagedClassNote[] = |
const char kOwnPtrToGCManagedClassNote[] = |
"[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; |
+const char kStackAllocatedFieldNote[] = |
+ "[blink-gc] Stack-allocated field %0 declared here:"; |
+ |
const char kPartObjectContainsGCRoot[] = |
"[blink-gc] Field %0 with embedded GC root in %1 declared here:"; |
@@ -97,6 +100,14 @@ const char kBaseRequiresFinalizationNote[] = |
const char kFieldRequiresFinalizationNote[] = |
"[blink-gc] Field %0 requiring finalization declared here:"; |
+const char kDerivesNonStackAllocated[] = |
+ "[blink-gc] Stack-allocated class %0 derives class %1" |
+ " which is not stack allocated."; |
+ |
+const char kDerivesStackAllocated[] = |
+ "[blink-gc] Class %0 derives stack-allocated class %1" |
+ " but is not itself stack allocated"; |
+ |
struct BlinkGCPluginOptions { |
BlinkGCPluginOptions() : enable_oilpan(false) {} |
bool enable_oilpan; |
@@ -419,11 +430,12 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { |
typedef std::vector<std::pair<FieldPoint*, Edge*> > Errors; |
CheckFieldsVisitor(const BlinkGCPluginOptions& options) |
- : options_(options), current_(0) {} |
+ : options_(options), current_(0), stack_allocated_host_(false) {} |
Errors& invalid_fields() { return invalid_fields_; } |
bool ContainsInvalidFields(RecordInfo* info) { |
+ stack_allocated_host_ = info->IsStackAllocated(); |
for (RecordInfo::Fields::iterator it = info->GetFields().begin(); |
it != info->GetFields().end(); |
++it) { |
@@ -439,6 +451,9 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { |
if (edge->value()->record()->isUnion()) |
return; |
+ if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) |
+ invalid_fields_.push_back(std::make_pair(current_, edge)); |
+ |
if (!Parent() || !edge->value()->IsGCAllocated()) |
return; |
@@ -449,13 +464,15 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { |
if (options_.enable_oilpan) |
return; |
- if (Parent()->IsRawPtr() || Parent()->IsRefPtr()) |
+ if ((!stack_allocated_host_ && Parent()->IsRawPtr()) || |
+ Parent()->IsRefPtr()) |
invalid_fields_.push_back(std::make_pair(current_, Parent())); |
} |
private: |
const BlinkGCPluginOptions& options_; |
FieldPoint* current_; |
+ bool stack_allocated_host_; |
Errors invalid_fields_; |
}; |
@@ -503,6 +520,10 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
getErrorLevel(), kMissingFinalize); |
diag_missing_finalize_dispatch_ = diagnostic_.getCustomDiagID( |
getErrorLevel(), kMissingFinalizeDispatch); |
+ diag_derives_non_stack_allocated_ = diagnostic_.getCustomDiagID( |
+ getErrorLevel(), kDerivesNonStackAllocated); |
+ diag_derives_stack_allocated_ = diagnostic_.getCustomDiagID( |
+ getErrorLevel(), kDerivesStackAllocated); |
// Register note messages. |
diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID( |
@@ -513,6 +534,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); |
diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( |
DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); |
+ diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID( |
+ DiagnosticsEngine::Note, kStackAllocatedFieldNote); |
diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( |
DiagnosticsEngine::Note, kPartObjectContainsGCRoot); |
diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( |
@@ -574,10 +597,22 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
// Check a class-like object (eg, class, specialization, instantiation). |
void CheckClass(RecordInfo* info) { |
- // Don't enforce tracing of stack allocated objects. |
- if (!info || info->IsStackAllocated()) |
+ if (!info) |
return; |
+ // Check consistency of stack-allocated hierarchies. |
+ bool stack_allocated = info->IsStackAllocated(); |
+ for (RecordInfo::Bases::iterator it = info->GetBases().begin(); |
+ it != info->GetBases().end(); |
+ ++it) { |
+ bool stack_allocated_base = it->second.info()->IsStackAllocated(); |
+ if (stack_allocated && !stack_allocated_base) |
+ ReportDerivesNonStackAllocated(info, &it->second); |
+ |
+ if (!stack_allocated && stack_allocated_base) |
+ ReportDerivesStackAllocated(info, &it->second); |
+ } |
+ |
if (info->RequiresTraceMethod() && !info->GetTraceMethod()) |
ReportClassRequiresTraceMethod(info); |
@@ -880,6 +915,8 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
NoteField(it->first, diag_ref_ptr_to_gc_managed_class_note_); |
} else if (it->second->IsOwnPtr()) { |
NoteField(it->first, diag_own_ptr_to_gc_managed_class_note_); |
+ } else if (it->second->IsValue()) { |
+ NoteField(it->first, diag_stack_allocated_field_note_); |
} |
} |
} |
@@ -973,6 +1010,22 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
diagnostic_.Report(full_loc, error) << receiver->record(); |
} |
+ void ReportDerivesNonStackAllocated(RecordInfo* info, BasePoint* base) { |
+ SourceLocation loc = base->spec().getLocStart(); |
+ SourceManager& manager = instance_.getSourceManager(); |
+ FullSourceLoc full_loc(loc, manager); |
+ diagnostic_.Report(full_loc, diag_derives_non_stack_allocated_) |
+ << info->record() << base->info()->record(); |
+ } |
+ |
+ void ReportDerivesStackAllocated(RecordInfo* info, BasePoint* base) { |
+ SourceLocation loc = base->spec().getLocStart(); |
+ SourceManager& manager = instance_.getSourceManager(); |
+ FullSourceLoc full_loc(loc, manager); |
+ diagnostic_.Report(full_loc, diag_derives_stack_allocated_) |
+ << info->record() << base->info()->record(); |
+ } |
+ |
void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) { |
NoteField(field, diag_field_requires_tracing_note_); |
} |
@@ -1036,11 +1089,14 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
unsigned diag_missing_trace_dispatch_; |
unsigned diag_missing_finalize_; |
unsigned diag_missing_finalize_dispatch_; |
+ unsigned diag_derives_non_stack_allocated_; |
+ unsigned diag_derives_stack_allocated_; |
unsigned diag_field_requires_tracing_note_; |
unsigned diag_raw_ptr_to_gc_managed_class_note_; |
unsigned diag_ref_ptr_to_gc_managed_class_note_; |
unsigned diag_own_ptr_to_gc_managed_class_note_; |
+ unsigned diag_stack_allocated_field_note_; |
unsigned diag_part_object_contains_gc_root_note_; |
unsigned diag_field_contains_gc_root_note_; |
unsigned diag_finalized_field_note_; |