report

49
Going Native Highlights Introduction to Variadic Templates. Clang overview.

description

From Dropbox

Transcript of report

Page 1: report

Going Native HighlightsIntroduction to Variadic Templates.

Clang overview.

Page 2: report

Quickoffice Proprietary and Confidential - Not for Disclosure 2

Variadic Templates

• Fundamentals• Usage• Samples

Page 3: report

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)

{

}

Page 4: report

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!

Page 5: report

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);

}

Page 6: report

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)

Page 7: report

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)... {}

Page 8: report

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();

}

Page 9: report

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)...);

}

Page 10: report

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);

Page 11: report

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

Page 12: report

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(); }

Page 13: report

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)...);

}

Page 14: report

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");

}

}

Page 15: report

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.");}

Page 16: report

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)...);

}

Page 17: report

Quickoffice Proprietary and Confidential - Not for Disclosure 17

Clang

• Motivation• Diagnostics• Static analysis• Dynamic analysis• Current state• Tool sample

Page 18: report

Quickoffice Proprietary and Confidential - Not for Disclosure 18

Why?

• Performance• Diagnostics• Tools

Page 19: report

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

Page 20: report

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

Page 21: report

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;}

Page 22: report

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); }

Page 23: report

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.

Page 24: report

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);}

Page 25: report

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

Page 26: report

Quickoffice Proprietary and Confidential - Not for Disclosure 26

Diagnostics

struct BaseType {};struct DerivedType : public BaseType { static int base_type; DerivedType() : basetype() {}};

Page 27: report

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.

Page 28: report

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;}

Page 29: report

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.

Page 30: report

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>();}

Page 31: report

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.

Page 32: report

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)); // ...}

Page 33: report

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.

Page 34: report

Quickoffice Proprietary and Confidential - Not for Disclosure 34

Diagnostics

int foo() { int arr[42]; // ... return arr[42];}

Page 35: report

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.

Page 36: report

Quickoffice Proprietary and Confidential - Not for Disclosure 36

Diagnostics

static const long long DiskCacheSize = 8 << 30; // 8 Gigs

Page 37: report

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.

Page 38: report

Quickoffice Proprietary and Confidential - Not for Disclosure 38

Diagnostics

void test(bool b, double x, double y){ if (b || x < y && x > 0) { // ... }}

Page 39: report

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.

Page 40: report

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;}

Page 41: report

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.

Page 42: report

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(); }}

Page 43: report

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(); }}

Page 44: report

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(); }}

Page 45: report

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.

Page 46: report

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

Page 47: report

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

Page 48: report

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 ”; } }};

Page 49: report

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.