CarlosAlbertoEnciso created this revision. CarlosAlbertoEnciso added reviewers: rsmith, erichkeane, probinson, dblaikie. CarlosAlbertoEnciso added a project: clang. Herald added a subscriber: aprantl.
The following submission under review https://reviews.llvm.org/D44826 introduced an option to warn on unused 'using declarations'. But it can't detect cases like namespace nsp { void foo(); int var; }using var using foo; <-- warning using var; <-- MISSING warning void bar() { using foo; <-- warning using var; <-- warning } void bar() { nsp::var = 1; } One of the reviewers (dblaikie) mentioned the possible cause for that limitation. You mention a missed case in the description - where the target of a using decl is used and that causes the unused-using not to warn about the using decl? That seems like a big limitation. Does that mean the 'used' bit is being tracked in the wrong place, on the target of the using decl instead of on the using decl itself? When a declaration is found to be ODR, only its associated 'Used' bit is set. This patch, traverse its associated declarations and sets the 'Used' bit. The goal is to create additional information to help in the reduction of the debug information size, which is affected by extra generation of 'non-used' declarations. Note: To solve the debug information issue (size), there are 3 pieces of work: - Set the 'Used' bit recursively. This patch. - Review the - Wunused-usings and -Wunused-local-typedefs implementation to take advantage of new 'Used' settings. - Do not generate debug information for the unused using Thanks for your view on this issue and on the general approach. Repository: rC Clang https://reviews.llvm.org/D46190 Files: include/clang/Sema/Sema.h include/clang/Sema/SemaInternal.h lib/AST/ASTDumper.cpp lib/AST/DeclBase.cpp lib/Sema/Sema.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLambda.cpp lib/Sema/SemaOpenMP.cpp lib/Sema/SemaStmt.cpp lib/Sema/SemaStmtAsm.cpp test/Frontend/float16.cpp test/Misc/ast-dump-attr.cpp test/Misc/ast-dump-color.cpp test/PCH/cxx-templates.cpp test/SemaCXX/used_class_struct_union.cpp test/SemaCXX/used_enum.cpp test/SemaCXX/used_goto.cpp test/SemaCXX/used_pointer.cpp test/SemaCXX/used_template.cpp test/SemaCXX/used_typedef.cpp test/SemaCXX/used_using.cpp
Index: test/SemaCXX/used_using.cpp =================================================================== --- test/SemaCXX/used_using.cpp +++ test/SemaCXX/used_using.cpp @@ -0,0 +1,162 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +namespace A { + typedef char CHAR; +} + +//CHECK: |-NamespaceDecl {{.*}} used A +//CHECK-NEXT: | `-TypedefDecl {{.*}} used CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +namespace B { + typedef char CHAR; +} + +//CHECK: |-NamespaceDecl {{.*}} used B +//CHECK-NEXT: | `-TypedefDecl {{.*}} used CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +namespace C { + typedef char CHAR; + typedef int INTEGER; + typedef unsigned UNSIGNED; + + void FA(); + void FB(); + + int Var1; + int Var2; +} + +//CHECK: |-NamespaceDecl {{.*}} used C +//CHECK-NEXT: | |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} UNSIGNED 'unsigned int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-FunctionDecl {{.*}} used FA 'void ()' +//CHECK-NEXT: | |-FunctionDecl {{.*}} used FB 'void ()' +//CHECK-NEXT: | |-VarDecl {{.*}} used Var1 'int' +//CHECK-NEXT: | `-VarDecl {{.*}} used Var2 'int' + +using A::CHAR; +using B::CHAR; + +//CHECK: |-UsingDecl {{.*}} A::CHAR +//CHECK-NEXT: |-UsingShadowDecl {{.*}} 'CHAR' +//CHECK-NEXT: | `-TypedefType {{.*}} 'A::CHAR' sugar +//CHECK-NEXT: | |-Typedef {{.*}} +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-UsingDecl {{.*}} B::CHAR +//CHECK-NEXT: |-UsingShadowDecl {{.*}} 'CHAR' +//CHECK-NEXT: | `-TypedefType {{.*}} 'B::CHAR' sugar +//CHECK-NEXT: | |-Typedef {{.*}} 'CHAR' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +void F1() { + using A::CHAR; + CHAR ca; + ca = '1'; + + using B::CHAR; + B::CHAR cb; + cb = '1'; +} + +//CHECK: |-FunctionDecl {{.*}} used F1 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} used A::CHAR +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} used ca 'A::CHAR':'char' +//CHECK-NEXT: | |-BinaryOperator {{.*}} +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'ca' 'A::CHAR':'char' +//CHECK-NEXT: | | `-CharacterLiteral {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} B::CHAR +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} used cb 'B::CHAR':'char' +//CHECK-NEXT: | `-BinaryOperator {{.*}} +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'cb' 'B::CHAR':'char' +//CHECK-NEXT: | `-CharacterLiteral {{.*}} + +void F2() { + using C::FA; + FA(); + + using C::Var1; + Var1 = 2; + + using C::FB; + C::FB(); + + using C::Var2; + C::Var2 = 2; +} + +//CHECK: |-FunctionDecl {{.*}} used F2 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} used C::FA +//CHECK-NEXT: | |-CallExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} used C::Var1 +//CHECK-NEXT: | |-BinaryOperator {{.*}} +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} C::FB +//CHECK-NEXT: | |-CallExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'FB' 'void ()' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDecl {{.*}} C::Var2 +//CHECK-NEXT: | `-BinaryOperator {{.*}} +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'Var2' 'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} + +void F3() { + using namespace C; + C::FA(); + + namespace CC = C; + using namespace CC; + CC::FA(); +} + +//CHECK: |-FunctionDecl {{.*}} used F3 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDirectiveDecl {{.*}} Namespace {{.*}} 'C' +//CHECK-NEXT: | |-CallExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'FA' 'void ()' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-NamespaceAliasDecl {{.*}} used CC +//CHECK-NEXT: | | `-Namespace {{.*}} 'C' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-UsingDirectiveDecl {{.*}} Namespace {{.*}} 'C' +//CHECK-NEXT: | `-CallExpr {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'FA' 'void ()' + +void Bar() { + F1(); + F2(); + F3(); +} + +//CHECK: `-FunctionDecl {{.*}} Bar 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CallExpr {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'F1' 'void ()' +//CHECK-NEXT: |-CallExpr {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'F2' 'void ()' +//CHECK-NEXT: `-CallExpr {{.*}} +//CHECK-NEXT: `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: `-DeclRefExpr {{.*}} 'F3' 'void ()' Index: test/SemaCXX/used_typedef.cpp =================================================================== --- test/SemaCXX/used_typedef.cpp +++ test/SemaCXX/used_typedef.cpp @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +namespace A { + typedef int INTEGER; + typedef char CHAR; + namespace B { + typedef int INTEGER; + typedef char CHAR; + struct S { + typedef int INTEGER; + typedef char CHAR; + }; + } +} + +//CHECK: |-NamespaceDecl {{.*}} used A +//CHECK-NEXT: | |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | `-NamespaceDecl {{.*}} used B +//CHECK-NEXT: | |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | `-CXXRecordDecl {{.*}} used struct S definition +//CHECK-NEXT: | |-DefinitionData {{.*}} +//CHECK-NEXT: | | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | | |-CopyConstructor {{.*}} +//CHECK-NEXT: | | |-MoveConstructor {{.*}} +//CHECK-NEXT: | | |-CopyAssignment {{.*}} +//CHECK-NEXT: | | |-MoveAssignment {{.*}} +//CHECK-NEXT: | | `-Destructor {{.*}} +//CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit struct S +//CHECK-NEXT: | |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | `-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +typedef int INTEGER; +typedef char CHAR; + +//CHECK: |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +void Foo() { + typedef char CHAR; + + typedef int INTEGER; + INTEGER L_I; + L_I = 1; + + ::INTEGER G_I; + G_I = 1; + + A::B::S::INTEGER M_N_S_I; + M_N_S_I = 1; + + A::B::INTEGER M_N_I; + M_N_I = 1; + + A::INTEGER M_I; + M_I = 1; +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-TypedefDecl {{.*}} CHAR 'char' +//CHECK-NEXT: | `-BuiltinType {{.*}} 'char' +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} 'int' +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used L_I 'INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} 'INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'INTEGER':'int' lvalue Var {{.*}} 'L_I' 'INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used G_I '::INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} '::INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} '::INTEGER':'int' lvalue Var {{.*}} 'G_I' '::INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used M_N_S_I 'A::B::S::INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} 'A::B::S::INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'A::B::S::INTEGER':'int' lvalue Var {{.*}} 'M_N_S_I' 'A::B::S::INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used M_N_I 'A::B::INTEGER':'int' +//CHECK-NEXT: |-BinaryOperator {{.*}} 'A::B::INTEGER':'int' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'A::B::INTEGER':'int' lvalue Var {{.*}} 'M_N_I' 'A::B::INTEGER':'int' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1 +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used M_I 'A::INTEGER':'int' +//CHECK-NEXT: `-BinaryOperator {{.*}} 'A::INTEGER':'int' lvalue '=' +//CHECK-NEXT: |-DeclRefExpr {{.*}} 'A::INTEGER':'int' lvalue Var {{.*}} 'M_I' 'A::INTEGER':'int' +//CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 Index: test/SemaCXX/used_template.cpp =================================================================== --- test/SemaCXX/used_template.cpp +++ test/SemaCXX/used_template.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +template <class T> +T B(T param) { + typedef T TYPE; + typedef int I; + TYPE var; + var = 1; + return ++param; +} + +//CHECK: | `-FunctionDecl {{.*}} used B 'int (int)' +//CHECK-NEXT: | |-TemplateArgument type 'int' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used param 'int':'int' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-TypedefDecl {{.*}} used TYPE 'int':'int' +//CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} +//CHECK-NEXT: | | |-TemplateTypeParmType {{.*}} +//CHECK-NEXT: | | | `-TemplateTypeParm {{.*}} +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-TypedefDecl {{.*}} I 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} used var 'TYPE':'int' +//CHECK-NEXT: | |-BinaryOperator {{.*}} 'TYPE':'int' lvalue '=' +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | `-ReturnStmt {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-UnaryOperator {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} + +void Bar() { + B<int>(1); +} + +//CHECK: `-FunctionDecl {{.*}} Bar 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: `-CallExpr {{.*}} +//CHECK-NEXT: |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} +//CHECK-NEXT: `-IntegerLiteral {{.*}} Index: test/SemaCXX/used_pointer.cpp =================================================================== --- test/SemaCXX/used_pointer.cpp +++ test/SemaCXX/used_pointer.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +typedef int INTEGER; +typedef INTEGER INT; + +//CHECK: |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} used INT 'INTEGER':'int' +//CHECK-NEXT: | `-TypedefType {{.*}} +//CHECK-NEXT: | |-Typedef {{.*}} +//CHECK-NEXT: | `-BuiltinType {{.*}} + +struct S { + static int si; + INT fi; + void F() {} +}; + +//CHECK: |-CXXRecordDecl {{.*}} used struct S definition +//CHECK-NEXT: | |-DefinitionData {{.*}} +//CHECK-NEXT: | | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | | |-CopyConstructor {{.*}} +//CHECK-NEXT: | | |-MoveConstructor {{.*}} +//CHECK-NEXT: | | |-CopyAssignment {{.*}} +//CHECK-NEXT: | | |-MoveAssignment {{.*}} +//CHECK-NEXT: | | `-Destructor {{.*}} +//CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit struct S +//CHECK-NEXT: | |-VarDecl {{.*}} used si 'int' static +//CHECK-NEXT: | |-FieldDecl {{.*}} used fi 'INT':'int' +//CHECK-NEXT: | |-CXXMethodDecl {{.*}} F 'void ()' +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'const S &' +//CHECK-NEXT: | `-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | `-ParmVarDecl {{.*}} 'S &&' + +void Bar(S *ps) { + ps->fi = 0; +} + +//CHECK: |-FunctionDecl {{.*}} used Bar 'void (S *)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used ps 'S *' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | `-BinaryOperator {{.*}} +//CHECK-NEXT: | |-MemberExpr {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'ps' 'S *' +//CHECK-NEXT: | `-IntegerLiteral {{.*}} + +void Foo() { + S s; + Bar(&s); + S::si = 2; +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used s 'S' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} +//CHECK-NEXT: |-CallExpr {{.*}} +//CHECK-NEXT: | |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'Bar' 'void (S *)' +//CHECK-NEXT: | `-UnaryOperator {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 's' 'S' +//CHECK-NEXT: `-BinaryOperator {{.*}} +//CHECK-NEXT: |-DeclRefExpr {{.*}} 'si' 'int' +//CHECK-NEXT: `-IntegerLiteral {{.*}} Index: test/SemaCXX/used_goto.cpp =================================================================== --- test/SemaCXX/used_goto.cpp +++ test/SemaCXX/used_goto.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +void Foo(int p) { +start: + int a; + typedef int INT; + if (p) { + goto end; + do { + } while (--p); + } + +end: + return; +} + +void Bar() { + Foo(2); +} + +//CHECK: |-FunctionDecl {{.*}} used Foo 'void (int)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used p 'int' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-LabelStmt {{.*}} 'start' +//CHECK-NEXT: | | |-LabelDecl {{.*}} start +//CHECK-NEXT: | | `-DeclStmt {{.*}} +//CHECK-NEXT: | | `-VarDecl {{.*}} a 'int' +//CHECK-NEXT: | |-DeclStmt {{.*}} +//CHECK-NEXT: | | `-TypedefDecl {{.*}} INT 'int' +//CHECK-NEXT: | | `-BuiltinType {{.*}} +//CHECK-NEXT: | |-IfStmt {{.*}} +//CHECK-NEXT: | | |-<<<NULL>>> +//CHECK-NEXT: | | |-<<<NULL>>> +//CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'p' 'int' +//CHECK-NEXT: | | |-CompoundStmt {{.*}} +//CHECK-NEXT: | | | |-GotoStmt {{.*}} 'end' {{.*}} +//CHECK-NEXT: | | | `-DoStmt {{.*}} +//CHECK-NEXT: | | | |-CompoundStmt {{.*}} +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | | `-UnaryOperator {{.*}} +//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'p' 'int' +//CHECK-NEXT: | | `-<<<NULL>>> +//CHECK-NEXT: | `-LabelStmt {{.*}} 'end' +//CHECK-NEXT: | |-LabelDecl {{.*}} used end +//CHECK-NEXT: | `-ReturnStmt {{.*}} +//CHECK: `-FunctionDecl {{.*}} Bar 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: `-CallExpr {{.*}} +//CHECK-NEXT: |-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'Foo' 'void (int)' +//CHECK-NEXT: `-IntegerLiteral {{.*}} Index: test/SemaCXX/used_enum.cpp =================================================================== --- test/SemaCXX/used_enum.cpp +++ test/SemaCXX/used_enum.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +enum NUMBER { + ONE = 1, + TWO = 2 +}; + +//CHECK: |-EnumDecl {{.*}} used NUMBER +//CHECK-NEXT: | |-EnumConstantDecl {{.*}} ONE 'NUMBER' +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | `-EnumConstantDecl {{.*}} referenced TWO 'NUMBER' +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-IntegerLiteral {{.*}} + +enum LETTER { + A = 'a', + B = 'b', + C = 'c' +}; + +//CHECK: |-EnumDecl {{.*}} referenced LETTER +//CHECK-NEXT: | |-EnumConstantDecl {{.*}} A 'LETTER' +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-CharacterLiteral {{.*}} +//CHECK-NEXT: | |-EnumConstantDecl {{.*}} 'LETTER' +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-CharacterLiteral {{.*}} +//CHECK-NEXT: | `-EnumConstantDecl {{.*}} C 'LETTER' +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | `-CharacterLiteral {{.*}} + +void Foo() { + NUMBER n; + n = TWO; + LETTER l; +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used n 'NUMBER' +//CHECK-NEXT: |-BinaryOperator {{.*}} +//CHECK-NEXT: | |-DeclRefExpr {{.*}} 'n' 'NUMBER' +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'TWO' 'NUMBER' +//CHECK-NEXT: `-DeclStmt {{.*}} +//CHECK-NEXT: `-VarDecl {{.*}} l 'LETTER' Index: test/SemaCXX/used_class_struct_union.cpp =================================================================== --- test/SemaCXX/used_class_struct_union.cpp +++ test/SemaCXX/used_class_struct_union.cpp @@ -0,0 +1,133 @@ +// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace + +struct S { + void SF(int param) { + int var; + var = 1; + } +}; + +//CHECK: |-CXXRecordDecl {{.*}} used struct S definition +//CHECK-NEXT: | |-DefinitionData {{.*}} +//CHECK-NEXT: | | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | | |-CopyConstructor {{.*}} +//CHECK-NEXT: | | |-MoveConstructor {{.*}} +//CHECK-NEXT: | | |-CopyAssignment {{.*}} +//CHECK-NEXT: | | |-MoveAssignment {{.*}} +//CHECK-NEXT: | | `-Destructor {{.*}} +//CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit struct S +//CHECK-NEXT: | |-CXXMethodDecl {{.*}} used SF 'void (int)' +//CHECK-NEXT: | | |-ParmVarDecl {{.*}} used param 'int' +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | | |-DeclStmt {{.*}} +//CHECK-NEXT: | | | `-VarDecl {{.*}} used var 'int' +//CHECK-NEXT: | | `-BinaryOperator {{.*}} +//CHECK-NEXT: | | |-DeclRefExpr {{.*}} 'var' 'int' +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'const S &' +//CHECK-NEXT: | `-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | `-ParmVarDecl {{.*}} 'S &&' + +typedef int INTEGER; +typedef float FLOAT; + +//CHECK: |-TypedefDecl {{.*}} used INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} FLOAT 'float' +//CHECK-NEXT: | `-BuiltinType {{.*}} + +class C { + typedef float FLOAT; + typedef int INTEGER; + ::INTEGER i; + FLOAT f; +public: + C() : i(0), f(0.0) {} + C(::INTEGER pi) : i(pi), f(0.0) {} + C(::INTEGER pi,FLOAT pf) : i(pi), f(pf) {} + void CF() {} +}; + +//CHECK: |-CXXRecordDecl {{.*}} used class C definition +//CHECK-NEXT: |-DefinitionData {{.*}} +//CHECK-NEXT: | |-DefaultConstructor {{.*}} +//CHECK-NEXT: | |-CopyConstructor {{.*}} +//CHECK-NEXT: | |-MoveConstructor {{.*}} +//CHECK-NEXT: | |-CopyAssignment {{.*}} +//CHECK-NEXT: | |-MoveAssignment {{.*}} +//CHECK-NEXT: | `-Destructor {{.*}} +//CHECK-NEXT: |-CXXRecordDecl {{.*}} implicit referenced class C +//CHECK-NEXT: |-TypedefDecl {{.*}} used FLOAT 'float' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-TypedefDecl {{.*}} INTEGER 'int' +//CHECK-NEXT: | `-BuiltinType {{.*}} +//CHECK-NEXT: |-FieldDecl {{.*}} used i '::INTEGER':'int' +//CHECK-NEXT: |-FieldDecl {{.*}} used f 'C::FLOAT':'float' +//CHECK-NEXT: |-AccessSpecDecl {{.*}} public +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} used C 'void ()' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-IntegerLiteral {{.*}} +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-FloatingLiteral {{.*}} +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} used C 'void (::INTEGER)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used pi '::INTEGER':'int' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'pi' '::INTEGER':'int' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-FloatingLiteral {{.*}} +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} used C 'void (::INTEGER, C::FLOAT)' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used pi '::INTEGER':'int' +//CHECK-NEXT: | |-ParmVarDecl {{.*}} used pf 'C::FLOAT':'float' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'pi' '::INTEGER':'int' +//CHECK-NEXT: | |-CXXCtorInitializer {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'pf' 'C::FLOAT':'float' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXMethodDecl {{.*}} CF 'void ()' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: |-CXXConstructorDecl {{.*}} +//CHECK-NEXT: | `-ParmVarDecl {{.*}} 'const C &' +//CHECK-NEXT: `-CXXConstructorDecl {{.*}} +//CHECK-NEXT: `-ParmVarDecl {{.*}} 'C &&' + +void Foo() { + S r; + r.SF(1); + + C c1; + C c2(1); + C c3(1,1.1); +} + +//CHECK: `-FunctionDecl {{.*}} used Foo 'void ()' +//CHECK-NEXT: `-CompoundStmt {{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} used r 'S' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'S' 'void () noexcept' +//CHECK-NEXT: |-CXXMemberCallExpr {{.*}} +//CHECK-NEXT: | |-MemberExpr {{.*}} +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'r' 'S' +//CHECK-NEXT: | `-IntegerLiteral{{.*}} +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} 'C' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'C' 'void ()' +//CHECK-NEXT: |-DeclStmt {{.*}} +//CHECK-NEXT: | `-VarDecl {{.*}} 'C' callinit +//CHECK-NEXT: | `-CXXConstructExpr {{.*}} 'C' 'void (::INTEGER)' +//CHECK-NEXT: | `-IntegerLiteral{{.*}} +//CHECK-NEXT: `-DeclStmt {{.*}} +//CHECK-NEXT: `-VarDecl {{.*}} 'C' callinit +//CHECK-NEXT: `-CXXConstructExpr {{.*}} 'C' 'void (::INTEGER, C::FLOAT)' +//CHECK-NEXT: |-IntegerLiteral {{.*}} +//CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'C::FLOAT':'float' <FloatingCast> +//CHECK-NEXT: `-FloatingLiteral {{.*}} Index: test/PCH/cxx-templates.cpp =================================================================== --- test/PCH/cxx-templates.cpp +++ test/PCH/cxx-templates.cpp @@ -5,12 +5,12 @@ // Test with pch. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o - -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s // Test with modules. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump -o - -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s // Test with pch and delayed template parsing. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h @@ -28,7 +28,7 @@ }; void test(const int (&a6)[17]) { - int x = templ_f<int, 5>(3); + int x = templ_f<int, 5>(3);; S<char, float>::templ(); S<int, char>::partial(); Index: test/Misc/ast-dump-color.cpp =================================================================== --- test/Misc/ast-dump-color.cpp +++ test/Misc/ast-dump-color.cpp @@ -62,14 +62,14 @@ //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:8:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]> Text=" Comment"{{$}} -//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> [[Yellow]]line:18:33[[RESET]] class[[CYAN]] Mutex[[RESET]] definition{{$}} +//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> [[Yellow]]line:18:33[[RESET]] used class[[CYAN]] Mutex[[RESET]] definition{{$}} //CHECK: {{^}}[[Blue]]| |-[[RESET]][[BLUE]]CapabilityAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:22[[RESET]]> capability "mutex"{{$}} //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:33[[RESET]]> [[Yellow]]col:33[[RESET]] implicit class[[CYAN]] Mutex[[RESET]]{{$}} -//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:20:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]][[CYAN]] var1[[RESET]] [[Green]]'int'[[RESET]]{{$}} +//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:20:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]] used[[CYAN]] var1[[RESET]] [[Green]]'int'[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:19:6[[RESET]], [[Yellow]]col:16[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:16[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:16[[RESET]]> Text=" A variable"{{$}} -//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:24:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]][[CYAN]] var2[[RESET]] [[Green]]'int'[[RESET]]{{$}} +//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:24:3[[RESET]], [[Yellow]]col:7[[RESET]]> [[Yellow]]col:7[[RESET]] used[[CYAN]] var2[[RESET]] [[Green]]'int'[[RESET]]{{$}} //CHECK: {{^}}[[Blue]]| | `-[[RESET]][[Blue]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:21:6[[RESET]], [[Yellow]]line:23:44[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[Blue]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:21:6[[RESET]], [[Yellow]]col:22[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[Blue]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:22[[RESET]]> Text=" Another variable"{{$}} @@ -88,7 +88,7 @@ //CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:26:1[[RESET]], [[Yellow]]col:5[[RESET]]> [[Yellow]]col:5[[RESET]][[CYAN]] TestExpr[[RESET]] [[Green]]'int'[[RESET]] //CHECK: {{^}}[[Blue]]| `-[[RESET]][[BLUE]]GuardedByAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:29[[RESET]], [[Yellow]]col:43[[RESET]]>{{$}} //CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'Mutex'[[RESET]]{{$}} -//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] struct[[CYAN]] Invalid[[RESET]] definition +//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] used struct[[CYAN]] Invalid[[RESET]] definition //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit referenced struct[[CYAN]] Invalid[[RESET]] //CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:29:3[[RESET]], [[Yellow]]col:42[[RESET]]> [[Yellow]]col:29[[RESET]] invalid[[CYAN]] Invalid[[RESET]] [[Green]]'void (int)'[[RESET]] //CHECK: {{^}}[[Blue]]| | |-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:37[[RESET]], [[Yellow]]<invalid sloc>[[RESET]]> [[Yellow]]col:42[[RESET]] invalid [[Green]]'int'[[RESET]] Index: test/Misc/ast-dump-attr.cpp =================================================================== --- test/Misc/ast-dump-attr.cpp +++ test/Misc/ast-dump-attr.cpp @@ -95,12 +95,14 @@ // CHECK-NEXT: UnusedAttr{{.*}} M: __attribute(()) int j; -// CHECK: LabelStmt {{.*}} 'M' +// CHECK: LabelStmt {{.*}} 'M' +// CHECK-NEXT: LabelDecl // CHECK-NEXT: DeclStmt // CHECK-NEXT: VarDecl {{.*}} j 'int' N: __attribute(()) ; // CHECK: LabelStmt {{.*}} 'N' +// CHECK-NEXT: LabelDecl // CHECK-NEXT: NullStmt } Index: test/Frontend/float16.cpp =================================================================== --- test/Frontend/float16.cpp +++ test/Frontend/float16.cpp @@ -110,9 +110,9 @@ } }; -//CHECK: |-CXXRecordDecl {{.*}} referenced class C1 definition +//CHECK: |-CXXRecordDecl {{.*}} used class C1 definition //CHECK: | |-CXXRecordDecl {{.*}} implicit referenced class C1 -//CHECK-NEXT: | |-FieldDecl {{.*}} referenced f1c '_Float16' +//CHECK-NEXT: | |-FieldDecl {{.*}} used f1c '_Float16' //CHECK-NEXT: | |-VarDecl {{.*}} used f2c 'const _Float16' static //CHECK-NEXT: | |-FieldDecl {{.*}} f3c 'volatile _Float16' //CHECK-NEXT: | |-AccessSpecDecl Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -810,7 +810,7 @@ if (Label->isMSAsmLabel()) { // If we have previously created this label implicitly, mark it as used. - Label->markUsed(Context); + markAllUsed(Label, Context); } else { // Otherwise, insert it, but only resolve it if we have seen the label itself. std::string InternalName; Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -2306,7 +2306,7 @@ if (RangeVarType->isDependentType()) { // The range is implicitly used as a placeholder when it is dependent. - RangeVar->markUsed(Context); + markAllUsed(RangeVar, Context); // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill // them in properly when we instantiate the loop. @@ -2785,7 +2785,7 @@ SourceLocation LabelLoc, LabelDecl *TheDecl) { setFunctionHasBranchIntoScope(); - TheDecl->markUsed(Context); + markAllUsed(TheDecl, Context); return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc); } Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -848,7 +848,7 @@ SourceLocation Loc, bool RefersToCapture = false) { D->setReferenced(); - D->markUsed(S.Context); + S.markAllUsed(D, S.Context); return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), D, RefersToCapture, Loc, Ty, VK_LValue); @@ -1811,7 +1811,7 @@ // Mark variable as used. VD->setReferenced(); - VD->markUsed(Context); + markAllUsed(VD, Context); QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -802,7 +802,7 @@ NewVD->setReferenced(true); // FIXME: Pass in a VarDecl::InitializationStyle. NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle)); - NewVD->markUsed(Context); + markAllUsed(NewVD, Context); NewVD->setInit(Init); return NewVD; } @@ -1665,7 +1665,7 @@ Lambda->lookup( Context.DeclarationNames.getCXXOperatorName(OO_Call)).front()); CallOperator->setReferenced(); - CallOperator->markUsed(Context); + markAllUsed(CallOperator, Context); ExprResult Init = PerformCopyInitialization( InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType(), Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12569,7 +12569,7 @@ /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { - TheDecl->markUsed(Context); + markAllUsed(TheDecl, Context); // Create the AST node. The address of a label always has type 'void*'. return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); @@ -13969,7 +13969,7 @@ /// \brief Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool MightBeOdrUse) { + bool MightBeOdrUse, Expr *RefExpr) { assert(Func && "No function?"); Func->setReferenced(); @@ -14135,7 +14135,7 @@ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } - Func->markUsed(Context); + markAllUsed(Func, Context, RefExpr); } static void @@ -14491,7 +14491,7 @@ CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); Var->setReferenced(true); - Var->markUsed(S.Context); + S.markAllUsed(Var, S.Context); } // Actually capture the variable. @@ -15024,7 +15024,7 @@ SemaRef.MaybeODRUseExprs.insert(E); } else if (OdrUseContext) { MarkVarDeclODRUsed(Var, Loc, SemaRef, - /*MaxFunctionScopeIndex ptr*/ nullptr); + /*MaxFunctionScopeIndex ptr*/ nullptr, E); } else if (isOdrUseContext(SemaRef, /*SkipDependentUses*/false)) { // If this is a dependent context, we don't need to mark variables as // odr-used, but we may still need to track them for lambda capture. @@ -15072,7 +15072,7 @@ return; } - SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse, E); // If this is a call to a method via a cast, also mark the method in the // derived class used in case codegen can devirtualize the call. @@ -15093,7 +15093,7 @@ CXXMethodDecl *DM = MD->getDevirtualizedMethod( ME->getBase(), SemaRef.getLangOpts().AppleKext); if (DM) - SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse, E); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. @@ -15133,15 +15133,15 @@ /// functions and variables. This method should not be used when building a /// normal expression which refers to a variable. void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, - bool MightBeOdrUse) { + bool MightBeOdrUse, Expr *RefExpr) { if (MightBeOdrUse) { if (auto *VD = dyn_cast<VarDecl>(D)) { MarkVariableReferenced(Loc, VD); return; } } if (auto *FD = dyn_cast<FunctionDecl>(D)) { - MarkFunctionReferenced(Loc, FD, MightBeOdrUse); + MarkFunctionReferenced(Loc, FD, MightBeOdrUse, RefExpr); return; } D->setReferenced(); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -10717,7 +10717,7 @@ ? Constructor->getLocEnd() : Constructor->getLocation(); Constructor->setBody(new (Context) CompoundStmt(Loc)); - Constructor->markUsed(Context); + markAllUsed(Constructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -10893,7 +10893,7 @@ } Constructor->setBody(new (Context) CompoundStmt(InitLoc)); - Constructor->markUsed(Context); + markAllUsed(Constructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); @@ -11000,7 +11000,7 @@ ? Destructor->getLocEnd() : Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Loc)); - Destructor->markUsed(Context); + markAllUsed(Destructor, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Destructor); @@ -11809,7 +11809,7 @@ assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } CopyAssignOperator->setBody(Body.getAs<Stmt>()); - CopyAssignOperator->markUsed(Context); + markAllUsed(CopyAssignOperator, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyAssignOperator); @@ -12180,7 +12180,7 @@ assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } MoveAssignOperator->setBody(Body.getAs<Stmt>()); - MoveAssignOperator->markUsed(Context); + markAllUsed(MoveAssignOperator, Context); if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(MoveAssignOperator); @@ -12315,7 +12315,7 @@ Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); - CopyConstructor->markUsed(Context); + markAllUsed(CopyConstructor, Context); } if (ASTMutationListener *L = getASTMutationListener()) { @@ -12438,7 +12438,7 @@ Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt( Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); - MoveConstructor->markUsed(Context); + markAllUsed(MoveConstructor, Context); } if (ASTMutationListener *L = getASTMutationListener()) { @@ -12485,7 +12485,7 @@ // Fill in the __invoke function with a dummy implementation. IR generation // will fill in the actual details. Update its type in case it contained // an 'auto'. - Invoker->markUsed(Context); + markAllUsed(Invoker, Context); Invoker->setReferenced(); Invoker->setType(Conv->getReturnType()->getPointeeType()); Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); @@ -12497,7 +12497,7 @@ Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(), Conv->getLocation())); - Conv->markUsed(Context); + markAllUsed(Conv, Context); Conv->setReferenced(); if (ASTMutationListener *L = getASTMutationListener()) { @@ -12552,7 +12552,7 @@ Stmt *ReturnS = Return.get(); Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(), Conv->getLocation())); - Conv->markUsed(Context); + markAllUsed(Conv, Context); // We're done; notify the mutation listener, if any. if (ASTMutationListener *L = getASTMutationListener()) { Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" @@ -1869,3 +1870,641 @@ return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), FnName, OpenCLDeclExtMap, 1, D.getSourceRange()); } + +// Visitor to set the 'used' bit. +class UsedSetter : public RecursiveASTVisitor<UsedSetter> { +using VisitorBase = RecursiveASTVisitor<UsedSetter>; +public: + UsedSetter(Sema *S, ASTContext &C, Expr *RefExpr) : + S(S), C(C), CurContext(S->CurContext), RefExpr(RefExpr) {} + +public: + // C Types. + bool VisitArrayType(const ArrayType *T); + bool VisitAtomicType(const AtomicType *T); + bool VisitBlockPointerType(const BlockPointerType *T); + bool VisitEnumType(const EnumType *T); + bool VisitIncompleteArrayType(const IncompleteArrayType *T); + bool VisitParenType(const ParenType *T); + bool VisitPointerType(const PointerType *T); + bool VisitTypedefType(const TypedefType *T); + bool VisitVariableArrayType(const VariableArrayType *T); + + // C++ Types. + bool VisitAttributedType(const AttributedType *T); + bool VisitComplexType(const ComplexType *T); + bool VisitConstantArrayType(const ConstantArrayType *T); + bool VisitDecayedType(const DecayedType *T); + bool VisitDecltypeType(const DecltypeType *T); + bool VisitDependentSizedArrayType(const DependentSizedArrayType *T); + bool VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T); + bool VisitElaboratedType(const ElaboratedType *T); + bool VisitExtVectorType(const ExtVectorType *T); + bool VisitLValueReferenceType(const LValueReferenceType *T); + bool VisitMemberPointerType(const MemberPointerType *T); + bool VisitRecordType(const RecordType *T); + bool VisitReferenceType(const ReferenceType *T); + bool VisitRValueReferenceType(const RValueReferenceType *T); + bool VisitTypeOfType(const TypeOfType *T); + bool VisitUnaryTransformType(const UnaryTransformType *T); + bool VisitUnresolvedUsingType(const UnresolvedUsingType *T); + bool VisitVectorType(const VectorType *T); + + // ObjC Types. + bool VisitObjCInterfaceType(const ObjCInterfaceType *T); + bool VisitObjCObjectPointerType(const ObjCObjectPointerType *T); + bool VisitObjCObjectType(const ObjCObjectType *T); + + // C Decls. + bool VisitBlockDecl(const BlockDecl *D); + bool VisitDeclContext(DeclContext *DC); + bool VisitEnumConstantDecl(EnumConstantDecl *D); + bool VisitEnumDecl(EnumDecl *D); + bool VisitFieldDecl(FieldDecl *D); + bool VisitFunctionDecl(FunctionDecl *D); + bool VisitLabelDecl(LabelDecl *D); + bool VisitParmVarDecl(ParmVarDecl *D); + bool VisitRecordDecl(RecordDecl *D); + bool VisitTypedefDecl(TypedefNameDecl *D); + bool VisitVarDecl(VarDecl *D); + + // C++ Decls. + bool VisitCXXConstructorDecl(CXXConstructorDecl *D); + bool VisitCXXConversionDecl(CXXConversionDecl *D); + bool VisitCXXDestructorDecl(CXXDestructorDecl *D); + bool VisitCXXMethodDecl(CXXMethodDecl *D); + bool VisitCXXRecordDecl(CXXRecordDecl *D); + bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); + bool VisitTypeAliasDecl(TypeAliasDecl *D); + bool VisitUsingDecl(UsingDecl *D); + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + bool VisitUsingShadowDecl(UsingShadowDecl *D); + + // OpenMP Decls. + bool VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); + bool VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + bool VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + + // ObjC Decls. + bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); + bool VisitObjCCategoryDecl(ObjCCategoryDecl *D); + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + bool VisitObjCMethodDecl(ObjCMethodDecl *D); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *D); + bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + bool VisitObjCProtocolDecl(ObjCProtocolDecl *D); + +public: + bool VisitDecl(Decl *D); + +private: + // Mark usings dependencies. + void markSymbolFromNamespace(NamedDecl *D); + void markUsings(Decl *D, QualType T); + bool markUsings(DeclContext *LookupContext, NamedDecl *TargetDecl, + NamespaceDecl *TargetNamespace); + + // Mark parent context for given declaration. + void markParentContext(Decl *D); + +private: + Sema *S; + ASTContext &C; + DeclContext *CurContext; + Expr *RefExpr; +}; + +//===---------------------------------------------------------------------===// +// C Types. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitArrayType(const ArrayType *T) { + return TraverseType(T->getElementType()); +} +bool UsedSetter::VisitAtomicType(const AtomicType *T) { + return TraverseType(T->getValueType()); +} +bool UsedSetter::VisitBlockPointerType(const BlockPointerType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitEnumType(const EnumType *T) { + return VisitEnumDecl(T->getDecl()); +} +bool UsedSetter::VisitIncompleteArrayType(const IncompleteArrayType *T) { + return VisitArrayType(T); +} +bool UsedSetter::VisitParenType(const ParenType *T) { + return TraverseType(T->getInnerType()); +} +bool UsedSetter::VisitPointerType(const PointerType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitTypedefType(const TypedefType *T) { + return VisitTypedefDecl(T->getDecl()); +} +bool UsedSetter::VisitVariableArrayType(const VariableArrayType *T) { + return VisitArrayType(T); +} + +//===---------------------------------------------------------------------===// +// C++ Types. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitAttributedType(const AttributedType *T) { + return TraverseType(T->getModifiedType()); +} +bool UsedSetter::VisitComplexType(const ComplexType *T) { + return TraverseType(T->getElementType()); +} +bool UsedSetter::VisitConstantArrayType(const ConstantArrayType *T) { + return VisitArrayType(T); +} +bool UsedSetter::VisitDecayedType(const DecayedType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitDecltypeType(const DecltypeType *T) { + return TraverseType(T->getUnderlyingType()); +} +bool UsedSetter::VisitDependentSizedArrayType( + const DependentSizedArrayType *T) { + return VisitArrayType(T); +} +bool UsedSetter::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + return TraverseType(T->getElementType()); +} +bool UsedSetter::VisitElaboratedType(const ElaboratedType *T) { + return TraverseType(T->getNamedType()); +} +bool UsedSetter::VisitExtVectorType(const ExtVectorType *T) { + return VisitVectorType(T); +} +bool UsedSetter::VisitLValueReferenceType(const LValueReferenceType *T) { + return VisitReferenceType(T); +} +bool UsedSetter::VisitMemberPointerType(const MemberPointerType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitRecordType(const RecordType *T) { + return VisitRecordDecl(T->getDecl()); +} +bool UsedSetter::VisitReferenceType(const ReferenceType *T) { + return TraverseType(T->getPointeeType()); +} +bool UsedSetter::VisitRValueReferenceType(const RValueReferenceType *T) { + return VisitReferenceType(T); +} +bool UsedSetter::VisitTypeOfType(const TypeOfType *T) { + return TraverseType(T->getUnderlyingType()); +} +bool UsedSetter::VisitUnaryTransformType(const UnaryTransformType *T) { + return TraverseType(T->getUnderlyingType()); +} +bool UsedSetter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + return VisitUnresolvedUsingTypenameDecl(T->getDecl()); +} +bool UsedSetter::VisitVectorType(const VectorType *T) { + return TraverseType(T->getElementType()); +} + +//===---------------------------------------------------------------------===// +// ObjC Types. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + return true; +} +bool UsedSetter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + return true; +} +bool UsedSetter::VisitObjCObjectType(const ObjCObjectType *T) { + return true; +} + +//===---------------------------------------------------------------------===// +// C Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitBlockDecl(const BlockDecl *D) { + return true; +} +bool UsedSetter::VisitDeclContext(DeclContext *DC) { + // Base: CXXMethodDecl + if (auto *CD = dyn_cast<CXXConstructorDecl>(DC)) + return VisitCXXConstructorDecl(CD); + + // Base: CXXMethodDecl + if (auto *DD = dyn_cast<CXXDestructorDecl>(DC)) + return VisitCXXDestructorDecl(DD); + + // Base: CXXMethodDecl + if (auto *CD = dyn_cast<CXXConversionDecl>(DC)) + return VisitCXXConversionDecl(CD); + + // Base: FunctionDecl + if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) + return VisitCXXMethodDecl(MD); + + // Base: DeclaratorDecl + if (auto *FD = dyn_cast<FunctionDecl>(DC)) + return VisitFunctionDecl(FD); + + // Base: NamedDecl + if (auto *ND = dyn_cast<NamespaceDecl>(DC)) + return VisitNamespaceDecl(ND); + + // Base: TagDecl + if (auto *RD = dyn_cast<RecordDecl>(DC)) + return VisitRecordDecl(RD); + + // Base: Decl + if (auto *BD = dyn_cast<BlockDecl>(DC)) + return VisitBlockDecl(BD); + + return true; +} +bool UsedSetter::VisitEnumConstantDecl(EnumConstantDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return TraverseType(D->getType()); +} +bool UsedSetter::VisitEnumDecl(EnumDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return TraverseType(D->getPromotionType()); +} +bool UsedSetter::VisitFieldDecl(FieldDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark the field type. + auto T = D->getType(); + markUsings(D, T); + return TraverseType(T); +} +bool UsedSetter::VisitFunctionDecl(FunctionDecl *D) { + if (D->isUsed(false) && !RefExpr) + return true; + D->markUsed(C); + + markParentContext(D); + + // Mark parameters. + if (D->getNumParams()) + for (auto *PD : D->parameters()) + VisitParmVarDecl(PD); + + // Mark return type. + auto T = D->getReturnType(); + markUsings(D, T); + + // Check if the symbols referenced by a 'using' statement. + markSymbolFromNamespace(D); + + return TraverseType(T); +} +bool UsedSetter::VisitLabelDecl(LabelDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return VisitDeclContext(D->getDeclContext()); +} +bool UsedSetter::VisitParmVarDecl(ParmVarDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark the parameter type. + auto T = D->getType(); + markUsings(D, T); + return TraverseType(T); +} +bool UsedSetter::VisitRecordDecl(RecordDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark non-static fields. + for (auto *FD : D->fields()) + VisitFieldDecl(FD); + + markParentContext(D); + return true; +} +bool UsedSetter::VisitTypedefDecl(TypedefNameDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + markParentContext(D); + return TraverseType(D->getUnderlyingType()); +} +bool UsedSetter::VisitVarDecl(VarDecl *D) { + if (D->isUsed(false) && !RefExpr) + return true; + D->markUsed(C); + + markParentContext(D); + + // Mark the variable type. + auto T = D->getType(); + markUsings(D, T); + + // Check if the symbols referenced by a 'using' statement. + markSymbolFromNamespace(D); + + return TraverseType(T); +} + +//===---------------------------------------------------------------------===// +// C++ Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + return VisitCXXMethodDecl(D); +} +bool UsedSetter::VisitCXXConversionDecl(CXXConversionDecl *D) { + return VisitCXXMethodDecl(D); +} +bool UsedSetter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + return VisitCXXMethodDecl(D); +} +bool UsedSetter::VisitCXXMethodDecl(CXXMethodDecl *D) { + return VisitFunctionDecl(D); +} +bool UsedSetter::VisitCXXRecordDecl(CXXRecordDecl *D) { + return VisitRecordDecl(D); +} +bool UsedSetter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return VisitNamespaceDecl(D->getNamespace()); +} +bool UsedSetter::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + markParentContext(D); + return true; +} +bool UsedSetter::VisitTypeAliasDecl(TypeAliasDecl *D) { + if (D->isUsed(false)) + return true; + + return TraverseType(D->getUnderlyingType()); +} +bool UsedSetter::VisitUsingDecl(UsingDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return true; +} +bool UsedSetter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + return VisitNamespaceDecl(D->getNominatedNamespace()); +} +bool UsedSetter::VisitUsingShadowDecl(UsingShadowDecl *D) { + if (D->isUsed(false)) + return true; + D->markUsed(C); + + // Mark the associated using declaration. + return VisitUsingDecl(D->getUsingDecl()); +} + +//===---------------------------------------------------------------------===// +// OpenMP Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { + return true; +} +bool UsedSetter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + return true; +} +bool UsedSetter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { + return true; +} + +//===---------------------------------------------------------------------===// +// ObjC Decls. +//===---------------------------------------------------------------------===// +bool UsedSetter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + return true; +} +bool UsedSetter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + return true; +} +bool UsedSetter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { + return true; +} +bool UsedSetter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + return true; +} +bool UsedSetter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + return true; +} +bool UsedSetter::VisitObjCMethodDecl(ObjCMethodDecl *D) { + return true; +} +bool UsedSetter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + return true; +} +bool UsedSetter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + return true; +} +bool UsedSetter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { + return true; +} + +/// \brief For the given declaration, mark all its parent context as used. +void UsedSetter::markParentContext(Decl *D) { + // For the given declaration, mark its parent context. + for (auto *DC = D->getDeclContext(); + !isa<TranslationUnitDecl>(DC) && + !isa<LinkageSpecDecl>(DC) && D->isUsed(false); DC = DC->getParent()) + VisitDeclContext(DC); +} + +/// \brief For the given declaration (variable or function), mark as used +/// any associated 'using' statement. +void UsedSetter::markSymbolFromNamespace(NamedDecl *D) { + // For a function or variable declared in a namespace, check for 'using' + // statement. Use the context passed by Sema, as it corresponds to the + // context where the variable or function is being referenced. + auto *DC = D->getDeclContext(); + if (DC->isNamespace()) { + // Check if the referenced variable or function contains any named + // qualifiers. As this function can be called recursively, ignore + // the calls that do not refer to the original referenced variable + // or function. + DeclRefExpr *DRE; + if (RefExpr && (DRE = dyn_cast<DeclRefExpr>(RefExpr))) { + auto *VD = cast<ValueDecl>(DRE->getDecl()); + if (VD == D && !DRE->hasQualifier()) + if (markUsings(CurContext, D, dyn_cast<NamespaceDecl>(DC))) + return; + } + // Consider namespace aliases. + auto *TargetNamespace = dyn_cast<NamespaceDecl>(DC); + for (DC = CurContext; DC; DC = DC->getParent()) { + for (auto *DR : DC->decls()) + if (auto *NA = dyn_cast<NamespaceAliasDecl>(DR)) { + if (NA->getNamespace() == TargetNamespace) { + VisitNamespaceAliasDecl(NA); + return; + } + } + } + } +} + +/// \brief If the given type was introduced by a 'using' statement, mark its +// associated 'using' as used. +void UsedSetter::markUsings(Decl *D, QualType QT) { + // In the case of name qualified type, do not look for any reference to + // a 'using' declaration. + // namespace N { + // typedef int INT; + // } + // void foo { + // N::INT var; + // } + if (isa<ElaboratedType>(QT)) + return; + + NamedDecl *TargetDecl = nullptr; + auto *T = QT.getTypePtr(); + if (auto *TT = dyn_cast<TypedefType>(T)) + TargetDecl = TT->getDecl(); + else if (auto *RT = dyn_cast<RecordType>(T)) + TargetDecl = RT->getDecl(); + + if (TargetDecl) { + // To have a proper search on 'using' statements, we need to determine + // the correct lookup context, based on the symbol being marked as used. + // In the case of parameters, the lookup context is the enclosing scope. + auto *LookupContext = D->getDeclContext(); + if (D->getKind() == Decl::ParmVar) + LookupContext = LookupContext->getParent(); + + auto *DC = TargetDecl->getDeclContext(); + if (DC->isNamespace()) + markUsings(LookupContext, TargetDecl, dyn_cast<NamespaceDecl>(DC)); + } +} + +/// \brief If the given declaration was introduced by a 'using' statement, +// mark its associated 'using' as used. +bool UsedSetter::markUsings(DeclContext *LookupContext, NamedDecl *TargetDecl, + NamespaceDecl *TargetNamespace) { + // Look for an introduced declaration via a 'using' statement. + // Do not perform lookups into transparent contexts. + for (auto *DC = LookupContext; + DC && !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC); + DC = DC->getParent()) { + // The using-declaration are contained in the returned 'decls()'. + for (auto *DR : DC->decls()) + if (auto *USD = dyn_cast<UsingShadowDecl>(DR)) { + if (USD->getTargetDecl() == TargetDecl) { + VisitUsingShadowDecl(USD); + return true; + } + } + // Check for using-directives. + for (auto *UD : DC->using_directives()) + if (UD->getNominatedNamespace() == TargetNamespace) { + VisitUsingDirectiveDecl(UD); + return true; + } + } + + // Do not perform lookups into transparent contexts. + if (LookupContext->getDeclKind() == Decl::LinkageSpec || + LookupContext->getDeclKind() == Decl::Export) + return false; + + if (auto *scope = S->getScopeForContext(LookupContext)) + for (auto *UD : scope->using_directives()) + if (UD->getNominatedNamespace() == TargetNamespace) { + VisitUsingDirectiveDecl(UD); + return true; + } + + return false; +} + +bool UsedSetter::VisitDecl(Decl *D) { + // This is the main entry point to mark the given declaration as used. + // We deal only with functions and variables. + + // Base: CXXMethodDecl + if (auto *CD = dyn_cast<CXXConstructorDecl>(D)) + return VisitCXXConstructorDecl(CD); + + // Base: CXXMethodDecl + if (auto *DD = dyn_cast<CXXDestructorDecl>(D)) + return VisitCXXDestructorDecl(DD); + + // Base: CXXMethodDecl + if (auto *CD = dyn_cast<CXXConversionDecl>(D)) + return VisitCXXConversionDecl(CD); + + // Base: FunctionDecl + if (auto *MD = dyn_cast<CXXMethodDecl>(D)) + return VisitCXXMethodDecl(MD); + + // Base: DeclaratorDecl + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return VisitFunctionDecl(FD); + + // Base: VarDecl + if (auto *PD = dyn_cast<ParmVarDecl>(D)) + return VisitParmVarDecl(PD); + + // Base: DeclaratorDecl + if (auto *VD = dyn_cast<VarDecl>(D)) + return VisitVarDecl(VD); + + // Base: NamedDecl + if (auto *LD = dyn_cast<LabelDecl>(D)) + return VisitLabelDecl(LD); + + // For unsupported ObjC or OpenMP declarations. + D->markUsed(C); + return true; +} + +void Sema::markAllUsed(Decl *D, ASTContext &C, Expr *RefExpr) { + // When setting the 'used' bit for referenced variables or functions, the + // 'RefExpr' is the expression associated with that reference. Within the + // same context, the variable or function can be referenced more than once: + // namespace M { void Foo(); } + // namespace N { int a; } + // void Bar() { + // M::Foo(); <-- Marked as used. RefExpr1; + // using M::Foo; + // Foo(); <-- Already marked as used. RefExpr2; + // <-- We have to mark the 'using' statement. + // + // N::a = 1; <-- Marked as used. RefExpr3; + // using N::a; + // a = 2; <-- Already marked as used. RefExpr4; + // <-- We have to mark the 'using' statement. + // } + if (D->isUsed(false) && !RefExpr) + return; + + UsedSetter Setter(this, C, RefExpr); + Setter.VisitDecl(D); +} Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -410,9 +410,7 @@ } void Decl::markUsed(ASTContext &C) { - if (isUsed(false)) - return; - + // The 'markAllUsed' does the check for an already used declaration. if (C.getASTMutationListener()) C.getASTMutationListener()->DeclarationMarkedUsed(this); Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -1991,6 +1991,7 @@ void ASTDumper::VisitLabelStmt(const LabelStmt *Node) { VisitStmt(Node); OS << " '" << Node->getName() << "'"; + dumpDecl(Node->getDecl()); } void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { Index: include/clang/Sema/SemaInternal.h =================================================================== --- include/clang/Sema/SemaInternal.h +++ include/clang/Sema/SemaInternal.h @@ -69,7 +69,7 @@ // *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. inline void MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, - const unsigned *const FunctionScopeIndexToStopAt) { + const unsigned *const FunctionScopeIndexToStopAt, Expr *RefExpr = nullptr) { // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && @@ -87,7 +87,7 @@ CaptureType, DeclRefType, FunctionScopeIndexToStopAt); - Var->markUsed(SemaRef.Context); + SemaRef.markAllUsed(Var, SemaRef.Context, RefExpr); } /// Return a DLL attribute from the declaration. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -4007,9 +4007,11 @@ // odr-use cannot be determined from the current context (for instance, // because the name denotes a virtual function and was written without an // explicit nested-name-specifier). - void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse, + Expr *RefExpr = nullptr); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool MightBeOdrUse = true); + bool MightBeOdrUse = true, + Expr *RefExpr = nullptr); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); void MarkMemberReferenced(MemberExpr *E); @@ -10667,6 +10669,14 @@ CharUnits Alignment); public: + /// \brief Mark the declaration used, in the sense of odr-use. + /// + /// This notifies any mutation listeners in addition to setting a bit + /// indicating the declaration is used. It traverse its associated types + /// and mark them as used. Intended mainly for debug information. + void markAllUsed(Decl *D, ASTContext &C, Expr *RefExpr = nullptr); + +public: /// \brief Diagnoses the current set of gathered accesses. This typically /// happens at full expression level. The set is cleared after emitting the /// diagnostics.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits