0

Clang Plugin: Refactor CountType into ClassifyType

This CL refactors the logic for how types are weighed when considering
whether a type should have inline ctors/dtors allowed or not. It also
adds an option enabling template members which are themselves trivial
types ("trivial" being defined as types with trivial destructors) to not
be counted more heavily than non-template trivial members.

Bug: 1275317
Change-Id: Iac06d5caf9f6c1220671e03c8537aeafa0139315
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3329384
Reviewed-by: danakj chromium <danakj@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Will Cassella <cassew@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956172}
This commit is contained in:
Will Cassella
2022-01-06 18:13:57 +00:00
committed by Chromium LUCI CQ
parent 9987d64522
commit 64da6c539b
20 changed files with 539 additions and 70 deletions

@ -663,6 +663,8 @@ _BANNED_CPP_FUNCTIONS = (
'^chromecast/cast_core/runtime/browser',
# Fuchsia provides C++ libraries that use std::shared_ptr<>.
'.*fuchsia.*test\.(cc|h)',
# Needed for clang plugin tests
'^tools/clang/plugins/tests/',
_THIRD_PARTY_EXCEPT_BLINK], # Not an error in third_party folders.
),
(

@ -57,6 +57,8 @@ bool FindBadConstructsAction::ParseArgs(const CompilerInstance& instance,
options_.checked_ptr_as_trivial_member = true;
} else if (args[i] == "raw-ptr-template-as-trivial-member") {
options_.raw_ptr_template_as_trivial_member = true;
} else if (args[i] == "use-classify-type") {
options_.use_classify_type = true;
} else {
parsed = false;
llvm::errs() << "Unknown clang plugin argument: " << args[i] << "\n";

@ -384,10 +384,28 @@ void FindBadConstructsConsumer::CheckCtorDtorWeight(
for (RecordDecl::field_iterator it = record->field_begin();
it != record->field_end();
++it) {
CountType(it->getType().getTypePtr(),
&trivial_member,
&non_trivial_member,
&templated_non_trivial_member);
if (options_.use_classify_type) {
switch (ClassifyType(it->getType().getTypePtr())) {
case TypeClassification::kTrivial:
trivial_member += 1;
break;
case TypeClassification::kNonTrivial:
non_trivial_member += 1;
break;
case TypeClassification::kTrivialTemplate:
trivial_member += 1;
break;
case TypeClassification::kNonTrivialTemplate:
templated_non_trivial_member += 1;
break;
case TypeClassification::kNonTrivialExternTemplate:
non_trivial_member += 1;
break;
}
} else {
CountType(it->getType().getTypePtr(), &trivial_member,
&non_trivial_member, &templated_non_trivial_member);
}
}
// Check to see if we need to ban inlined/synthesized constructors. Note
@ -671,6 +689,132 @@ void FindBadConstructsConsumer::CheckVirtualBodies(
}
}
FindBadConstructsConsumer::TypeClassification
FindBadConstructsConsumer::ClassifyType(const Type* type) {
switch (type->getTypeClass()) {
case Type::Record: {
auto* record_decl = type->getAsCXXRecordDecl();
// Simplifying; the whole class isn't trivial if the dtor is, but
// we use this as a signal about complexity.
// Note that if a record doesn't have a definition, it doesn't matter how
// it's counted, since the translation unit will fail to build. In that
// case, just count it as a trivial member to avoid emitting warnings that
// might be spurious.
if (!record_decl->hasDefinition() || record_decl->hasTrivialDestructor())
return TypeClassification::kTrivial;
const auto name = record_decl->getQualifiedNameAsString();
// `std::basic_string` is externed by libc++, so even though it's a
// non-trivial type wrapped by a template, we shouldn't classify it as a
// `kNonTrivialTemplate`. The `kNonTrivialExternTemplate` classification
// exists for this purpose.
// https://github.com/llvm-mirror/libcxx/blob/78d6a7767ed57b50122a161b91f59f19c9bd0d19/include/string#L4317
if (name == "std::basic_string")
return TypeClassification::kNonTrivialExternTemplate;
// `base::raw_ptr` is non-trivial if the `use_backup_ref_ptr` flag is
// enabled, and trivial otherwise. Since there are many existing types
// using this that we don't wish to burden with defining custom
// ctors/dtors, and we'd rather not vary on triviality by build config,
// treat this as always trivial.
if (name == "base::raw_ptr")
return TypeClassification::kTrivialTemplate;
return TypeClassification::kNonTrivial;
}
case Type::TemplateSpecialization: {
// A "Template Specialization" is a type produced by providing arguments
// to any type template, not necessarily just a template which has
// explicitly declared specializations. This may be a regular type
// template, or a templated type alias.
//
// A great way to reason about templates is as a compile-time function
// taking compile-time arguments, and producing a regular type. In the
// context of a `TemplateSpecializationType`, we're referring to this
// particular invocation of that function. We can "desugar" that into the
// produced type, which is no longer seen as a template.
//
// Types produced by templates are of particular concern here, since they
// almost certainly have inline ctors/dtors and may result in lots of code
// being generated for types containing them. For that reason, non-trivial
// templates are weighted higher than regular non-trivial types.
auto* template_type = dyn_cast<TemplateSpecializationType>(type);
// If this is a template type alias, just consider the underlying type
// without the context of it being a template.
// For an example:
//
// template <typename T>
// using Foo = Bar<T>;
//
// Given `Foo<Baz>`, we want to classify it simply as `Bar<Baz>` would be.
if (template_type->isTypeAlias())
return ClassifyType(template_type->getAliasedType().getTypePtr());
// Otherwise, classify the type produced by the template and apply the
// corresponding template classification. For an example:
//
// template <typename T>
// struct Foo { ... };
//
// Given `Foo<Baz>`, classify `struct Foo { ... };` with `Baz` substituted
// for `T`;
const auto classification =
ClassifyType(template_type->desugar().getTypePtr());
if (classification == TypeClassification::kTrivial)
return TypeClassification::kTrivialTemplate;
if (classification == TypeClassification::kNonTrivial)
return TypeClassification::kNonTrivialTemplate;
return classification;
}
case Type::SubstTemplateTypeParm: {
// `SubstTemplateTypeParmType` appears wherever a template type parameter
// is encountered, and may be desugared into the type argument given to
// the template. For example:
//
// template <typename T>
// struct Foo {
// T bar; // <-- `bar` here is a `SubstTemplateTypeParmType`
// };
//
// or
//
// template <typename T>
// using Foo = T; // <-- `T` here is a `SubstTemplateTypeParmType`
const auto* const subst_type = dyn_cast<SubstTemplateTypeParmType>(type)
->getReplacementType()
.getTypePtr();
return ClassifyType(subst_type);
}
case Type::Elaborated: {
// Quote from the LLVM documentation:
// "Represents a type that was referred to using an elaborated type
// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, or
// both. This type is used to keep track of a type name as written in the
// source code, including tag keywords and any nested-name-specifiers. The
// type itself is always "sugar", used to express what was written in the
// source code but containing no additional semantic information."
return ClassifyType(
dyn_cast<ElaboratedType>(type)->getNamedType().getTypePtr());
}
case Type::Typedef: {
// A "typedef type" is the representation of a type named through a
// typedef (or a C++11 type alias). In this case, we don't care about the
// typedef itself, so we desugar it into the underlying type and classify
// that.
const auto* const decl = dyn_cast<TypedefType>(type)->getDecl();
return ClassifyType(decl->getUnderlyingType().getTypePtr());
}
default: {
// Stupid assumption: anything we see that isn't the above is a POD
// or reference type.
return TypeClassification::kTrivial;
}
}
}
void FindBadConstructsConsumer::CountType(const Type* type,
int* trivial_member,
int* non_trivial_member,

@ -84,6 +84,15 @@ class FindBadConstructsConsumer
void CheckVirtualSpecifiers(const clang::CXXMethodDecl* method);
void CheckVirtualBodies(const clang::CXXMethodDecl* method);
enum class TypeClassification {
kTrivial,
kNonTrivial,
kTrivialTemplate,
kNonTrivialTemplate,
kNonTrivialExternTemplate
};
TypeClassification ClassifyType(const clang::Type* type);
void CountType(const clang::Type* type,
int* trivial_member,
int* non_trivial_member,

@ -14,6 +14,7 @@ struct Options {
bool check_layout_object_methods = false;
bool checked_ptr_as_trivial_member = false;
bool raw_ptr_template_as_trivial_member = false;
bool use_classify_type = false;
};
} // namespace chrome_checker

@ -0,0 +1,5 @@
// Copyright (c) 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "atomic_member.h"

@ -0,0 +1 @@
-Xclang -plugin-arg-find-bad-constructs -Xclang use-classify-type

@ -0,0 +1,96 @@
// Copyright (c) 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_CLANG_PLUGINS_TESTS_ATOMIC_MEMBER_H_
#define TOOLS_CLANG_PLUGINS_TESTS_ATOMIC_MEMBER_H_
#include <atomic>
#include <memory>
// The standard says that std::atomic<Integral> (where Integral is a built-in
// integral type, including raw pointers) is a standard-layout struct, and has a
// trivial destructor:
// https://eel.is/c++draft/atomics.types.generic#atomics.types.int-2 Because of
// that, we classify std::atomic<Integral> as a trivial template.
struct NineAtomicIntAliasesOk {
std::atomic_int one;
std::atomic_int two;
std::atomic_int three;
std::atomic_int four;
std::atomic_int five;
std::atomic_int six;
std::atomic_int seven;
std::atomic_int eight;
std::atomic_int nine;
};
struct TenAtomicIntAliasesWarns {
std::atomic_int one;
std::atomic_int two;
std::atomic_int three;
std::atomic_int four;
std::atomic_int five;
std::atomic_int six;
std::atomic_int seven;
std::atomic_int eight;
std::atomic_int nine;
std::atomic_int ten;
};
struct NineAtomicIntTemplatesOk {
std::atomic<int> one;
std::atomic<int> two;
std::atomic<int> three;
std::atomic<int> four;
std::atomic<int> five;
std::atomic<int> six;
std::atomic<int> seven;
std::atomic<int> eight;
std::atomic<int> nine;
};
struct TenAtomicIntTemplatesWarns {
std::atomic<int> one;
std::atomic<int> two;
std::atomic<int> three;
std::atomic<int> four;
std::atomic<int> five;
std::atomic<int> six;
std::atomic<int> seven;
std::atomic<int> eight;
std::atomic<int> nine;
std::atomic<int> ten;
};
struct NineAtomicPtrsOk {
std::atomic<int*> one;
std::atomic<int*> two;
std::atomic<int*> three;
std::atomic<int*> four;
std::atomic<int*> five;
std::atomic<int*> six;
std::atomic<int*> seven;
std::atomic<int*> eight;
std::atomic<int*> nine;
};
struct TenAtomicPtrsWarns {
std::atomic<int*> one;
std::atomic<int*> two;
std::atomic<int*> three;
std::atomic<int*> four;
std::atomic<int*> five;
std::atomic<int*> six;
std::atomic<int*> seven;
std::atomic<int*> eight;
std::atomic<int*> nine;
std::atomic<int*> ten;
};
struct OneAtomicSharedPtrWarns {
std::atomic<std::shared_ptr<int>> one;
};
#endif // TOOLS_CLANG_PLUGINS_TESTS_ATOMIC_MEMBER_H_

@ -0,0 +1,15 @@
In file included from atomic_member.cpp:5:
./atomic_member.h:29:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
struct TenAtomicIntAliasesWarns {
^
./atomic_member.h:54:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
struct TenAtomicIntTemplatesWarns {
^
./atomic_member.h:79:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
struct TenAtomicPtrsWarns {
^
./atomic_member.h:92:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
struct OneAtomicSharedPtrWarns {
^
./atomic_member.h:92:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
5 warnings generated.

@ -1 +1 @@
-Xclang -plugin-arg-find-bad-constructs -Xclang checked-ptr-as-trivial-member -Xclang -plugin-arg-find-bad-constructs -Xclang raw-ptr-template-as-trivial-member
-Xclang -plugin-arg-find-bad-constructs -Xclang checked-ptr-as-trivial-member -Xclang -plugin-arg-find-bad-constructs -Xclang raw-ptr-template-as-trivial-member -Xclang -plugin-arg-find-bad-constructs -Xclang use-classify-type

@ -24,6 +24,14 @@ struct MyVector {
MyVector(MyVector&&);
};
template <class T>
struct TrivialTemplate {
TrivialTemplate();
};
template <typename T>
using AliasTemplate = T;
// Note: this should warn for an implicit copy constructor too, but currently
// doesn't, due to a plugin bug.
class MissingCtorsArentOKInHeader {
@ -127,6 +135,126 @@ class FourStringsWarns {
std::string four_;
};
class TrivialTemplateDoesNotWarn {
public:
TrivialTemplateDoesNotWarn() = default;
~TrivialTemplateDoesNotWarn() = default;
private:
TrivialTemplate<int> foo_;
};
class NineTrivialTemplatesDoesNotWarn {
public:
NineTrivialTemplatesDoesNotWarn() = default;
~NineTrivialTemplatesDoesNotWarn() = default;
private:
TrivialTemplate<int> one_;
TrivialTemplate<int> two_;
TrivialTemplate<int> three_;
TrivialTemplate<int> four_;
TrivialTemplate<int> five_;
TrivialTemplate<int> six_;
TrivialTemplate<int> seven_;
TrivialTemplate<int> eight_;
TrivialTemplate<int> nine_;
};
class TenTrivialTemplatesWarns {
public:
TenTrivialTemplatesWarns() = default;
~TenTrivialTemplatesWarns() = default;
private:
TrivialTemplate<int> one_;
TrivialTemplate<int> two_;
TrivialTemplate<int> three_;
TrivialTemplate<int> four_;
TrivialTemplate<int> five_;
TrivialTemplate<int> six_;
TrivialTemplate<int> seven_;
TrivialTemplate<int> eight_;
TrivialTemplate<int> nine_;
TrivialTemplate<int> ten_;
};
class TrivialAliasTemplateDoesNotWarn {
public:
TrivialAliasTemplateDoesNotWarn() = default;
~TrivialAliasTemplateDoesNotWarn() = default;
private:
AliasTemplate<int> one_;
};
class NineTrivialAliasTemplatesDoesNotWarn {
public:
NineTrivialAliasTemplatesDoesNotWarn() = default;
~NineTrivialAliasTemplatesDoesNotWarn() = default;
private:
AliasTemplate<int> one_;
AliasTemplate<int> two_;
AliasTemplate<int> three_;
AliasTemplate<int> four_;
AliasTemplate<int> five_;
AliasTemplate<int> six_;
AliasTemplate<int> seven_;
AliasTemplate<int> eight_;
AliasTemplate<int> nine_;
};
class TenTrivialAliasTemplatesWarns {
public:
TenTrivialAliasTemplatesWarns() = default;
~TenTrivialAliasTemplatesWarns() = default;
private:
AliasTemplate<int> one_;
AliasTemplate<int> two_;
AliasTemplate<int> three_;
AliasTemplate<int> four_;
AliasTemplate<int> five_;
AliasTemplate<int> six_;
AliasTemplate<int> seven_;
AliasTemplate<int> eight_;
AliasTemplate<int> nine_;
AliasTemplate<int> ten_;
};
class NonTrivialAliasTemplateDoesNotWarn {
public:
NonTrivialAliasTemplateDoesNotWarn() = default;
~NonTrivialAliasTemplateDoesNotWarn() = default;
private:
AliasTemplate<std::string> one_;
};
class ThreeNonTrivialAliasTemplatesDoesNotWarn {
public:
ThreeNonTrivialAliasTemplatesDoesNotWarn() = default;
~ThreeNonTrivialAliasTemplatesDoesNotWarn() = default;
private:
AliasTemplate<std::string> one_;
AliasTemplate<std::string> two_;
AliasTemplate<std::string> three_;
};
class FourNonTrivialAliasTemplatesWarns {
public:
FourNonTrivialAliasTemplatesWarns() = default;
~FourNonTrivialAliasTemplatesWarns() = default;
private:
AliasTemplate<std::string> one_;
AliasTemplate<std::string> two_;
AliasTemplate<std::string> three_;
AliasTemplate<std::string> four_;
};
class CheckedPtrDoesNotWarn {
public:
CheckedPtrDoesNotWarn() = default;

@ -1,24 +1,39 @@
In file included from missing_ctor.cpp:5:
./missing_ctor.h:29:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
./missing_ctor.h:37:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
class MissingCtorsArentOKInHeader {
^
./missing_ctor.h:29:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
./missing_ctor.h:55:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor.h:37:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
./missing_ctor.h:63:3: warning: [chromium-style] Complex constructor has an inlined body.
ExplicitlyDefaultedInlineAlsoWarns() = default;
^
./missing_ctor.h:57:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor.h:65:3: warning: [chromium-style] Complex constructor has an inlined body.
ExplicitlyDefaultedInlineAlsoWarns(
^
./missing_ctor.h:56:3: warning: [chromium-style] Complex destructor has an inline body.
./missing_ctor.h:64:3: warning: [chromium-style] Complex destructor has an inline body.
~ExplicitlyDefaultedInlineAlsoWarns() = default;
^
./missing_ctor.h:120:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor.h:128:3: warning: [chromium-style] Complex constructor has an inlined body.
FourStringsWarns() = default;
^
./missing_ctor.h:158:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor.h:129:3: warning: [chromium-style] Complex destructor has an inline body.
~FourStringsWarns() = default;
^
./missing_ctor.h:166:3: warning: [chromium-style] Complex constructor has an inlined body.
TenTrivialTemplatesWarns() = default;
^
./missing_ctor.h:210:3: warning: [chromium-style] Complex constructor has an inlined body.
TenTrivialAliasTemplatesWarns() = default;
^
./missing_ctor.h:248:3: warning: [chromium-style] Complex constructor has an inlined body.
FourNonTrivialAliasTemplatesWarns() = default;
^
./missing_ctor.h:249:3: warning: [chromium-style] Complex destructor has an inline body.
~FourNonTrivialAliasTemplatesWarns() = default;
^
./missing_ctor.h:286:3: warning: [chromium-style] Complex constructor has an inlined body.
TenCheckedPtrWarns() = default;
^
./missing_ctor.h:202:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor.h:330:3: warning: [chromium-style] Complex constructor has an inlined body.
TenRawPtrWarns() = default;
^
8 warnings generated.
13 warnings generated.

@ -9,6 +9,7 @@ struct MyString {
MyString();
MyString(const MyString&);
MyString(MyString&&);
~MyString();
};
template <class T>
@ -16,6 +17,7 @@ struct MyVector {
MyVector();
MyVector(const MyVector&);
MyVector(MyVector&&);
~MyVector();
};
// For now, this should only warn on the missing constructor, not on the missing

@ -1,14 +1,18 @@
In file included from missing_ctor_dllexport.cpp:5:
./missing_ctor_dllexport.h:23:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
./missing_ctor_dllexport.h:25:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
class __declspec(dllexport) MissingCtorsArentOKInHeader {
^
./missing_ctor_dllexport.h:47:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor_dllexport.h:25:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
./missing_ctor_dllexport.h:49:3: warning: [chromium-style] Complex constructor has an inlined body.
ExplicitlyDefaultedInlineAlsoWarns() = default;
^
./missing_ctor_dllexport.h:49:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor_dllexport.h:51:3: warning: [chromium-style] Complex constructor has an inlined body.
ExplicitlyDefaultedInlineAlsoWarns(
^
./missing_ctor_dllexport.h:51:3: warning: [chromium-style] Complex constructor has an inlined body.
./missing_ctor_dllexport.h:53:3: warning: [chromium-style] Complex constructor has an inlined body.
ExplicitlyDefaultedInlineAlsoWarns(ExplicitlyDefaultedInlineAlsoWarns&&) =
^
4 warnings generated.
./missing_ctor_dllexport.h:50:3: warning: [chromium-style] Complex destructor has an inline body.
~ExplicitlyDefaultedInlineAlsoWarns() = default;
^
6 warnings generated.

@ -0,0 +1,44 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_CLANG_PLUGINS_TESTS_SYSTEM_ATOMIC_
#define TOOLS_CLANG_PLUGINS_TESTS_SYSTEM_ATOMIC_
namespace std {
// Faux-implementation of std::atomic.
// The standard requires that the following conditions are met for `T`:
// std::is_copy_constructible<T>::value == true
// std::is_move_constructible<T>::value == true
// std::is_copy_assignable<T>::value == true
// std::is_move_assignable<T>::value == true
// std::is_trivially_copyable<T>::value == true
//
// An exception is made to the last condition for
// std::atomic<std::shared_ptr<T>> and std::atomic<std::weak_ptr<T>>, by
// defining partial-specializations in <memory>
//
// The standard also says that std::atomic<Integral> (where `Integral` is a
// built-in integral type, including raw pointers) is a standard-layout struct,
// and has a trivial destructor:
// https://eel.is/c++draft/atomics.types.generic#atomics.types.int-2
template <typename T>
struct atomic {
T i;
atomic();
~atomic() = default;
// std::atomic is never copyable or moveable
atomic(const atomic&) = delete;
atomic(atomic&&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(atomic&&) = delete;
};
using atomic_int = std::atomic<int>;
} // namespace std
#endif // TOOLS_CLANG_PLUGINS_TESTS_SYSTEM_ATOMIC_

@ -0,0 +1,42 @@
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_CLANG_PLUGINS_TESTS_SYSTEM_MEMORY_
#define TOOLS_CLANG_PLUGINS_TESTS_SYSTEM_MEMORY_
#include <atomic>
namespace std {
template <typename T>
struct shared_ptr {
shared_ptr();
~shared_ptr();
shared_ptr(const shared_ptr&);
shared_ptr(shared_ptr&&);
shared_ptr& operator=(const shared_ptr&);
shared_ptr& operator=(shared_ptr&&);
private:
T* ptr_ = nullptr;
};
// The STL has this specialization defined through <memory>.
// Normally template parameters to std::atomic must be trivially copyable,
// but exceptions are made for std::shared_ptr and std::weak_ptr.
template <typename T>
struct atomic<shared_ptr<T> > {
shared_ptr<T> i;
atomic();
~atomic();
atomic(const atomic&) = delete;
atomic(atomic&&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(atomic&&) = delete;
};
} // namespace std
#endif // TOOLS_CLANG_PLUGINS_TESTS_SYSTEM_MEMORY_

@ -8,7 +8,11 @@
namespace std {
template<typename CharType>
class basic_string {
struct basic_string {
basic_string();
basic_string(const basic_string&);
basic_string(basic_string&&);
~basic_string();
};
using string = basic_string<char>;

@ -8,7 +8,11 @@
namespace std {
template<typename T>
class vector {
struct vector {
vector();
vector(const vector&);
vector(vector&&);
~vector();
};
} // namespace std

@ -1,21 +0,0 @@
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "trivial_ctor.h"
// Due to https://bugs.chromium.org/p/chromium/issues/detail?id=663463, we treat
// templated classes/structs as non-trivial, even if they really are trivial.
// Thus, classes that have such a class/struct as a member get flagged as being
// themselves non-trivial, even if (like |MySpinLock|) they are. Special-case
// [std::]atomic_int.
class TrivialTemplateOK {
private:
MySpinLock lock_;
};
int main() {
MySpinLock lock;
TrivialTemplateOK one;
return 0;
}

@ -1,28 +0,0 @@
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TRIVIAL_CTOR_H_
#define TRIVIAL_CTOR_H_
// Mocked for testing:
namespace std {
template<typename T>
struct atomic {
T i;
};
typedef atomic<int> atomic_int;
} // namespace std
struct MySpinLock {
MySpinLock();
~MySpinLock();
MySpinLock(const MySpinLock&);
MySpinLock(MySpinLock&&);
std::atomic_int lock_;
};
#endif // TRIVIAL_CTOR_H_