report
-
Upload
quickoffice-test -
Category
Documents
-
view
329 -
download
2
description
Transcript of report
Going Native HighlightsIntroduction to Variadic Templates.
Clang overview.
Quickoffice Proprietary and Confidential - Not for Disclosure 2
Variadic Templates
• Fundamentals• Usage• Samples
Quickoffice Proprietary and Confidential - Not for Disclosure 3
Fundamentals
Class declaration:
template <typename... Ts>
class A
{
};
Function declaration:
template <typename... Ts>
void foo(const Ts&... vs)
{
}
Quickoffice Proprietary and Confidential - Not for Disclosure 4
What is Ts and vs?
• Ts is an alias for a list of types• vs is an alias for a list of values
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
Quickoffice Proprietary and Confidential - Not for Disclosure 5
Parameters Packs Usage
• Get pack size
size_t items = sizeof...(Ts); // or vs
• Expand back
template <typename... Ts>
void foo(const Ts&... Vs) {
goo(1, std::forward<Ts>(vs)..., 42);
}
Quickoffice Proprietary and Confidential - Not for Disclosure 6
Expansion rules
Usage Expansion result
Ts... T1, … , Tn
Ts&... T1&, … , Tn&
A<Ts, B>::foo... A<T1, B>::foo , … , A<Tn, B>::foo
A<const Ts&, Us>... A<const T1&, U1>, … , A<const Tn&, Un>
pow(vs, 42)... pow(v1, 42), … , pow(vn, 42)
Quickoffice Proprietary and Confidential - Not for Disclosure 7
Where to use?
• Initializer listsint a[] = { vs... };
• Base class specifiertemplate <typename... Ts>
struct A : B<Ts>...
{
};
• Class members initializer liststemplate <typename... Us>
A(Us... vs) : B<Ts>(vs)... {}
Quickoffice Proprietary and Confidential - Not for Disclosure 8
Where to use?
• Template arguments listsstd::map<Ts...> foo;
• Exception specifications
• Capture liststemplate <class... Ts>
void foo(Ts... vs) {
auto lamda = [&vs...] { return goo(vs...); }
lamda();
}
Quickoffice Proprietary and Confidential - Not for Disclosure 9
Multiple expansions
template <class... Ts>
void foo(Ts... vs)
{
goo(A<Ts...>::hoo(vs)...);
goo(A<Ts...>::hoo(vs...));
goo(A<Ts>::hoo(vs)...);
}
Quickoffice Proprietary and Confidential - Not for Disclosure 10
Where is used?
• std::make_shared
template<class T, class... Ts>
shared_ptr<T> make_shared(Ts&&... vs);
• std::vector::emplace_back
template <class... Args>
void emplace_back(Args&&... args);
Quickoffice Proprietary and Confidential - Not for Disclosure 11
Typesafe printf
• Stock printf:– Fast– Thread-safe– Convenient– Ubiquitously known– Utterly unsafe
• Goal: add verification of the provided parameters
Quickoffice Proprietary and Confidential - Not for Disclosure 12
Typesafe printf
• Adaptation routinestemplate <class T>
Typename enable_if<is_integral<T>::value, long>::type
normalizeArg(T arg) { return arg; }
template <class T>
typename enable_if<is_floating_point<T>::value, double>::type
normalizeArg(T arg) { return arg; }
template <class T>
typename enable_if<is_pointer<T>::value, T>::type
normalizeArg(T arg) { return arg; }
const char* normalizeArg(const string& arg)
{ return arg.c_str(); }
Quickoffice Proprietary and Confidential - Not for Disclosure 13
Typesafe printf
// Not really safe yet
template <typename... Ts>
int safe_printf(const char* format, const Ts&... ts)
{
return printf(format, normalizeArg(ts)...);
}
Quickoffice Proprietary and Confidential - Not for Disclosure 14
Typesafe printf
• Implement verification routine for argument-less call
void check_printf(const char * f)
{
for (; *f; ++f)
{
if (*f != ’%’ || *++f == ’%’) continue;
throw Exc("Bad format");
}
}
Quickoffice Proprietary and Confidential - Not for Disclosure 15
Typesafe printf
template <class T, typename... Ts>void check_printf(const char * f, const T& t, const Ts&... ts){ for (; *f; ++f) { if (*f != ’%’ || *++f == ’%’) continue; switch (*f) { default: throw Exc("Invalid format char: %", *f); case ’f’: case ’g’: ENFORCE(is_floating_point<T>::value); break; case ’s’: . . . } return check_printf(++f, ts...); // AHA!!! } throw Exc("Too few format specifiers.");}
Quickoffice Proprietary and Confidential - Not for Disclosure 16
Typesafe printf
• Final step
template <typename... Ts>
int safe_printf(const char* format, const Ts&... ts)
{
check_printf(format, normalizeArg(ts)...);
return printf(format, normalizeArg(ts)...);
}
Quickoffice Proprietary and Confidential - Not for Disclosure 17
Clang
• Motivation• Diagnostics• Static analysis• Dynamic analysis• Current state• Tool sample
Quickoffice Proprietary and Confidential - Not for Disclosure 18
Why?
• Performance• Diagnostics• Tools
Quickoffice Proprietary and Confidential - Not for Disclosure 19
Why?
int w = 0;for (int i = 0; i < 3; i++) w += w * 2;
$ gcc -fsyntax-only test.ctest.c:2: error: expected identifier or ‘(’ before ‘for’test.c:2: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or
‘__attribute__’ before ‘<’ tokentest.c:2: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or
‘__attribute__’ before ‘++’ token
Quickoffice Proprietary and Confidential - Not for Disclosure 20
Why?
“... is there a reason for not making the [GCC] front ends dynamic librarieswhich could be linked by any program that wants to parse source code?”
“One of our main goals for GCC is to prevent any parts of it from being used together with
non-free software. Thus, we have deliberately avoided many things that might possibly have
the effect of facilitating such usage...”- Richard Stallman
Quickoffice Proprietary and Confidential - Not for Disclosure 21
Why?
#define FOO 0int foo() { int x; // ... x = x + FOO; // ... return x;}
#define FOO 0int foo() { int x; // ... x = x; // ... return x;}
Quickoffice Proprietary and Confidential - Not for Disclosure 22
Diagnostics
template <int N> struct S1 { int arr[N - 5]; };template <typename T> struct S2 { S1<sizeof(T)> s1; };template <typename T> void foo(T x) { S2<T> s2; }void test() { foo(42); }
Quickoffice Proprietary and Confidential - Not for Disclosure 23
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:1:38: error: 'arr' declared as an array with a negative
sizetemplate <int N> struct S1 { int arr[N - 5]; }; ^~~~~test.cpp:2:49: note: in instantiation of template class 'S1<4>'
requested heretemplate <typename T> struct S2 { S1<sizeof(T)> s1; }; ^test.cpp:3:45: note: in instantiation of template class 'S2<int>'
requested heretemplate <typename T> void foo(T x) { S2<T> s2; } ^test.cpp:4:15: note: in instantiation of function template
specialization 'foo<int>' requested herevoid test() { foo(42); } ^1 error generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 24
Diagnostics
#define M1(x, y, z) y();#define M2(x, y, z) M1(x, y, z)void test() { M2(a, b, c);}
Quickoffice Proprietary and Confidential - Not for Disclosure 25
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:4:11: error: use of undeclared identifier 'b’ M2(a, b, c); ^test.cpp:2:27: note: expanded from macro 'M2'#define M2(x, y, z) M1(x, y, z) ^test.cpp:1:21: note: expanded from macro 'M1'#define M1(x, y, z) y(); ^1 error generated.
$ g++ -fsyntax-only test.cpp test.cpp: In function ‘void test()’:test.cpp:4: error: ‘b’ was not declared in this scope
Quickoffice Proprietary and Confidential - Not for Disclosure 26
Diagnostics
struct BaseType {};struct DerivedType : public BaseType { static int base_type; DerivedType() : basetype() {}};
Quickoffice Proprietary and Confidential - Not for Disclosure 27
Diagnostics
% clang++ -std=c++11 -fsyntax-only typo1.cpptypo1.cpp:4:19: error: initializer 'basetype' does not
name a non-static data member or base class; did you mean the base class 'BaseType’?
DerivedType() : basetype() {} ^~~~~~~~ BaseTypetypo1.cpp:2:22: note: base class 'BaseType' specified herestruct DerivedType : public BaseType { ^~~~~~~~~~~~~~~
1 error generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 28
Diagnostics
#include <sys/stat.h>int foo(int x, struct stat* P){ return P->st_blocksize * 2;}
Quickoffice Proprietary and Confidential - Not for Disclosure 29
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:3:13: error: no member named 'st_blocksize' in
'stat'; did you mean 'st_blksize'? return P->st_blocksize*2; ^~~~~~~~~~~~ st_blksize/usr/include/sys/stat.h:225:13: note: 'st_blksize'
declared herestruct stat __DARWIN_STRUCT_STAT64; ^/usr/include/sys/stat.h:212:12: note: expanded from macro
'__DARWIN_STRUCT_STAT64' blksize_t st_blksize; /*... */ \ ^1 error generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 30
Diagnostics
template <class T, class U> struct S {};template <typename... Ts> void f(Ts...);
template <typename... Ts> struct X { template <typename... Us> void g() { f(S<Ts, Us>()...); }};
void test(X<int, float> x){ x.g<int, float, double>();}
Quickoffice Proprietary and Confidential - Not for Disclosure 31
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:8:22: error: pack expansion contains parameter
packs 'Ts' and 'Us' that have different lengths (2 vs. 3)
f(S<Ts, Us>()...); ~~ ~~ ^test.cpp:14:7: note: in instantiation of function template
specialization 'X<int, float>::g<int, float, double>' requested here
x.g<int, float, double>(); ^1 error generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 32
Diagnostics
#include <memory.h>struct S { int a, b, c; float vec[16]; };void test(S *s) { // ... memset(s, 0, sizeof(s)); // ...}
Quickoffice Proprietary and Confidential - Not for Disclosure 33
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:5:25: warning: argument to 'sizeof' in 'memset'
call is the same expression as the destination; did you mean to dereference it? [-Wsizeof-pointer-memaccess]
memset(s, 0, sizeof(s)); ~ ^1 warning generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 34
Diagnostics
int foo() { int arr[42]; // ... return arr[42];}
Quickoffice Proprietary and Confidential - Not for Disclosure 35
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:4:12: warning: array index of '42' indexes past
the end of an array (that contains 42 elements) [-Warray-bounds]
return arr[42]; ^ ~~test.cpp:2:5: note: array 'arr' declared here int arr[42]; ^1 warning generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 36
Diagnostics
static const long long DiskCacheSize = 8 << 30; // 8 Gigs
Quickoffice Proprietary and Confidential - Not for Disclosure 37
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:2:23: warning: signed shift result (0x200000000)
requires 35 bits to represent, but 'int' only has 32 bits [-Wshift-overflow]
DiskCacheSize = 8 << 30; // 8 Gigs ~ ^ ~~1 warning generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 38
Diagnostics
void test(bool b, double x, double y){ if (b || x < y && x > 0) { // ... }}
Quickoffice Proprietary and Confidential - Not for Disclosure 39
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:2:19: warning: '&&' within '||' [-Wlogical-op-
parentheses] if (b || x < y && x > 0) { ~~ ~~~~~~^~~~~~~~test.cpp:2:19: note: place parentheses around the '&&'
expression to silence this warning if (b || x < y && x > 0) { ^ ( )1 warning generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 40
Diagnostics
constexpr int arr_size = 42;constexpr int N = 44;void f(int);int test(){ int arr[arr_size]; // ... f(arr[N]); // ... if (N < arr_size) return arr[N]; return 0;}
Quickoffice Proprietary and Confidential - Not for Disclosure 41
Diagnostics
$ clang++ -std=c++11 -fsyntax-only test.cpptest.cpp:7:7: warning: array index of '44' indexes past
the end of an array (that contains 42 elements) [-Warray-bounds]
f(arr[N]); ^ ~test.cpp:5:5: note: array 'arr' declared here int arr[arr_size]; ^1 warning generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 42
Static Analysis
struct mutex { void lock(); void unlock();};
mutex m;int x;bool foo();bool bar();void test() { m.lock(); while (foo()) { m.unlock(); if (bar()) { if (x < 42 && foo()) { continue; } } m.lock(); }}
Quickoffice Proprietary and Confidential - Not for Disclosure 43
Static Analysis
struct [[ts::lockable]] mutex { void lock() [[ts::exclusive_lock_function]]; void unlock() [[ts::unlock_function]];};
mutex m;int x [[ts::guarded_by(m)]];bool foo() [[ts::exclusive_locks_required(m)]];bool bar();void test() { m.lock(); while (foo()) { m.unlock(); if (bar()) { if (x < 42 && foo()) { continue; } } m.lock(); }}
Quickoffice Proprietary and Confidential - Not for Disclosure 44
Static Analysis
struct __attribute__((lockable)) mutex { void lock() __attribute__((exclusive_lock_function)); void unlock() __attribute__((unlock_function));};
mutex m;int x __attribute__((guarded_by(m)));bool foo() __attribute__((exclusive_locks_required(m)));bool bar();void test() { m.lock(); while (foo()) { m.unlock(); if (bar()) { if (x < 42 && foo()) { continue; } } m.lock(); }}
Quickoffice Proprietary and Confidential - Not for Disclosure 45
Diagnostics
$ clang++ -std=c++11 -fsyntax-only -Wthread-safety test.cpp
test.cpp:11:5: warning: expecting mutex 'm' to be locked at start of each loop [-Wthread-safety]
m.lock(); ^test.cpp:11:5: warning: mutex 'm' is still locked at the
end of function [-Wthread-safety]test.cpp:15:17: warning: reading variable 'x' requires
locking 'm' [-Wthread-safety] if (x < 42 && foo()) { ^test.cpp:19:9: warning: mutex 'm' is still locked at the
end of its scope [-Wthread-safety] m.lock(); ^4 warnings generated.
Quickoffice Proprietary and Confidential - Not for Disclosure 46
Current Status
• Platforms:+ Linux+ Mac OS X– Windows
• C++11 features:+ Almost all features implemented in v2.9+/SVN– Missing features:
• Generalized attributes• Inheriting constructors• Concurrency
Quickoffice Proprietary and Confidential - Not for Disclosure 47
Brief architecture overview
• GCC compatible• Library based architecture– libsupport, libsystem, libbasic, libast, liblex, libparse, libsema,
libcodegen, librewrite, libanalysis, libindex
• One kind of as AST for C++/C and Objective-C• Visitor interface ASTConsumer for Front-end actions
Quickoffice Proprietary and Confidential - Not for Disclosure 48
Sample ASTConsumer
class PrintFunctionsConsumer : public ASTConsumer{public: virtual void HandleTopLevelDecl(DeclGroupRef DG) { for (DeclGroupRef::iterator it = DG.begin(); it != DG.end(); ++it) { const Decl* D = *it; if (const NamedDecl* ND = dyn_cast<NamedDecl>(D)) llvm::errs() << ” topleveldecl : \” ” << ND->getNameAsString() << ” \” \n ”; } }};
Quickoffice Proprietary and Confidential - Not for Disclosure 49
Thirdparty tools
http://code.google.com/p/include-what-you-use/
"Include what you use" means this: for every symbol (type, function variable, or macro) that you use in foo.cc, either foo.cc or foo.h should #include a .h file that exports the declaration of that symbol. The include-what-you-use tool is a program that can be built with the clang libraries in order to analyze #includes of source files to find include-what-you-use violations, and suggest fixes for them.