llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Fred Tingaud (frederic-tingaud-sonarsource) <details> <summary>Changes</summary> When getting the source range of the implicit instantiation of a class template, we get the source range of the latest declaration of the class template, even when it is not its definition. The problem does not occur with function templates and variable templates. This patch aligns the behavior of class templates with function and variable templates. --- Full diff: https://github.com/llvm/llvm-project/pull/156011.diff 5 Files Affected: - (modified) clang/lib/AST/DeclTemplate.cpp (+6-1) - (modified) clang/test/AST/ast-dump-decl.cpp (+3-3) - (modified) clang/test/AST/ast-dump-openmp-begin-declare-variant_template_3.cpp (+2-2) - (modified) clang/test/AST/ast-dump-template-decls-json.cpp (+2-2) - (added) clang/test/AST/ast-dump-template-redecl.cpp (+88) ``````````diff diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 3162857aac5d0..01cc33b795308 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1050,7 +1050,12 @@ ClassTemplateSpecializationDecl::getSourceRange() const { if (const auto *CTPSD = dyn_cast<ClassTemplatePartialSpecializationDecl *>(Pattern)) return CTPSD->getSourceRange(); - return cast<ClassTemplateDecl *>(Pattern)->getSourceRange(); + + const auto *CTD = cast<ClassTemplateDecl *>(Pattern); + if (CTD->getTemplatedDecl()->hasDefinition()) + return CTD->getTemplatedDecl()->getDefinition()->getSourceRange(); + + return CTD->getSourceRange(); } case TSK_ExplicitSpecialization: { SourceRange Range = CXXRecordDecl::getSourceRange(); diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index afb507833d869..8d7aed69520b4 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -334,7 +334,7 @@ namespace testClassTemplateDecl { // CHECK-NEXT: | |-CXXDestructorDecl 0x[[#%x,TEMPLATE_DESTRUCTOR_DECL:]] <line:[[@LINE-50]]:5, col:24> col:5 ~TestClassTemplate<T> 'void ()' not_selected{{$}} // CHECK-NEXT: | |-CXXMethodDecl 0x[[#%x,TEMPLATE_METHOD_DECL:]] <line:[[@LINE-50]]:5, col:11> col:9 j 'int ()'{{$}} // CHECK-NEXT: | `-FieldDecl 0x{{.+}} <line:[[@LINE-50]]:5, col:9> col:9 i 'int'{{$}} -// CHECK-NEXT: |-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-56]]:3, line:[[@LINE-50]]:3> line:[[@LINE-56]]:30 class TestClassTemplate definition implicit_instantiation{{$}} +// CHECK-NEXT: |-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-56]]:24, line:[[@LINE-50]]:3> line:[[@LINE-56]]:30 class TestClassTemplate definition implicit_instantiation{{$}} // CHECK-NEXT: | |-DefinitionData standard_layout has_user_declared_ctor can_const_default_init{{$}} // CHECK-NEXT: | | |-DefaultConstructor exists non_trivial user_provided{{$}} // CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param{{$}} @@ -635,7 +635,7 @@ namespace testCanonicalTemplate { // CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} parent 0x{{.+}} <col:5, col:40> col:40 friend_undeclared TestClassTemplate{{$}} // CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} <col:14, col:23> col:23 typename depth 1 index 0 T2{{$}} // CHECK-NEXT: | `-CXXRecordDecl 0x{{.+}} parent 0x{{.+}} <col:34, col:40> col:40 class TestClassTemplate{{$}} - // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-19]]:3, line:[[@LINE-17]]:3> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}} + // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-19]]:25, line:[[@LINE-17]]:3> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}} // CHECK-NEXT: |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}} // CHECK-NEXT: | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr{{$}} // CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param implicit_has_const_param{{$}} @@ -668,7 +668,7 @@ namespace testCanonicalTemplate { // CHECK: ClassTemplateDecl 0x{{.+}} <{{.+}}:[[@LINE-5]]:3, col:31> col:31 TestClassTemplate2{{$}} // CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <col:12, col:21> col:21 typename depth 0 index 0 T1{{$}} // CHECK-NEXT: |-CXXRecordDecl 0x{{.+}} <col:25, col:31> col:31 class TestClassTemplate2{{$}} - // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-6]]:3, line:[[@LINE-5]]:3> line:[[@LINE-6]]:31 class TestClassTemplate2 definition implicit_instantiation{{$}} + // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-6]]:25, line:[[@LINE-5]]:3> line:[[@LINE-6]]:31 class TestClassTemplate2 definition implicit_instantiation{{$}} // CHECK-NEXT: |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}} // CHECK-NEXT: | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr{{$}} // CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param implicit_has_const_param{{$}} diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_3.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_3.cpp index 44d1cb462cd58..779dfec42ea8e 100644 --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_3.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_3.cpp @@ -59,7 +59,7 @@ int test() { // CHECK-NEXT: | | |-ParmVarDecl [[ADDR_5:0x[a-z0-9]*]] <col:5> col:8 'int' // CHECK-NEXT: | | |-ParmVarDecl [[ADDR_6:0x[a-z0-9]*]] <col:10, col:12> col:13 'T *' // CHECK-NEXT: | | `-CompoundStmt [[ADDR_7:0x[a-z0-9]*]] <col:15, col:16> -// CHECK-NEXT: | |-ClassTemplateSpecializationDecl [[ADDR_8:0x[a-z0-9]*]] <line:5:1, line:7:1> line:5:30 struct S definition +// CHECK-NEXT: | |-ClassTemplateSpecializationDecl [[ADDR_8:0x[a-z0-9]*]] <line:5:23, line:7:1> line:5:30 struct S definition // CHECK-NEXT: | | |-DefinitionData pass_in_registers empty standard_layout trivially_copyable has_user_declared_ctor can_const_default_init // CHECK-NEXT: | | | |-DefaultConstructor defaulted_is_constexpr // CHECK-NEXT: | | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param @@ -82,7 +82,7 @@ int test() { // CXX17-NEXT: | | |-CXXConstructorDecl [[ADDR_16:0x[a-z0-9]*]] <col:30> col:30 implicit constexpr S 'void (S<int> &&)' inline default trivial noexcept-unevaluated // CXX17-NEXT: | | | `-ParmVarDecl [[ADDR_17:0x[a-z0-9]*]] <col:30> col:30 'S<int> &&' // CHECK-NEXT: | | `-CXXDestructorDecl [[ADDR_19:0x[a-z0-9]*]] <col:30> col:30 implicit referenced {{(constexpr )?}}~S 'void ({{.*}}) noexcept' inline default trivial -// CHECK-NEXT: | `-ClassTemplateSpecializationDecl [[ADDR_20:0x[a-z0-9]*]] <col:1, line:7:1> line:5:30 struct S +// CHECK-NEXT: | `-ClassTemplateSpecializationDecl [[ADDR_20:0x[a-z0-9]*]] <col:23, line:7:1> line:5:30 struct S // CHECK-NEXT: | `-TemplateArgument type 'double' // CHECK-NEXT: | `-BuiltinType [[ADDR_21:0x[a-z0-9]*]] 'double' // CHECK-NEXT: |-FunctionTemplateDecl [[ADDR_22:0x[a-z0-9]*]] <line:9:1, line:12:1> line:10:5 also_before diff --git a/clang/test/AST/ast-dump-template-decls-json.cpp b/clang/test/AST/ast-dump-template-decls-json.cpp index 70f1d3b55f3ee..240469955f4b6 100644 --- a/clang/test/AST/ast-dump-template-decls-json.cpp +++ b/clang/test/AST/ast-dump-template-decls-json.cpp @@ -2872,8 +2872,8 @@ W(int)->W<1>; // CHECK-NEXT: "range": { // CHECK-NEXT: "begin": { // CHECK-NEXT: "offset": {{[0-9]+}}, -// CHECK-NEXT: "col": 1, -// CHECK-NEXT: "tokLen": 8 +// CHECK-NEXT: "col": 18, +// CHECK-NEXT: "tokLen": 5 // CHECK-NEXT: }, // CHECK-NEXT: "end": { // CHECK-NEXT: "offset": {{[0-9]+}}, diff --git a/clang/test/AST/ast-dump-template-redecl.cpp b/clang/test/AST/ast-dump-template-redecl.cpp new file mode 100644 index 0000000000000..a883375c1630b --- /dev/null +++ b/clang/test/AST/ast-dump-template-redecl.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s %std_cxx17- | FileCheck %s --check-prefixes=CHECK +// expected-no-diagnostics + +template <class T> +struct Redeclared { + void function() {} +}; + +template <class T> +struct Redeclared; + +Redeclared<int> instantiation; + +template <typename T> +void redeclaredFunction(T t) { + (void)t; +} + +template <typename T> +void redeclaredFunction(T t); + +void instantiate() { + redeclaredFunction(0); +} + + +// CHECK: |-ClassTemplateDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}:4:1, line:7:1> line:5:8 Redeclared +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_1:0x[a-z0-9]*]] <line:4:11, col:17> col:17 class depth 0 index 0 T +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_2:0x[a-z0-9]*]] <line:5:1, line:7:1> line:5:8 struct Redeclared definition +// CHECK-NEXT: | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr +// CHECK-NEXT: | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | | `-Destructor simple irrelevant trivial {{(constexpr )?}}needs_implicit +// CHECK-NEXT: | | |-CXXRecordDecl [[ADDR_3:0x[a-z0-9]*]] <col:1, col:8> col:8 implicit struct Redeclared +// CHECK-NEXT: | | `-CXXMethodDecl [[ADDR_4:0x[a-z0-9]*]] <line:6:3, col:20> col:8 function 'void ()' implicit-inline +// CHECK-NEXT: | | `-CompoundStmt [[ADDR_5:0x[a-z0-9]*]] <col:19, col:20> +// CHECK-NEXT: | `-ClassTemplateSpecializationDecl [[ADDR_6:0x[a-z0-9]*]] <line:5:1, line:7:1> line:5:8 struct Redeclared definition implicit_instantiation +// CHECK-NEXT: | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init +// CHECK-NEXT: | | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr +// CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param +// CHECK-NEXT: | | |-MoveConstructor exists simple trivial +// CHECK-NEXT: | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | |-MoveAssignment exists simple trivial needs_implicit +// CHECK-NEXT: | | `-Destructor simple irrelevant trivial constexpr needs_implicit +// CHECK-NEXT: | |-TemplateArgument type 'int' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_7:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_8:0x[a-z0-9]*]] <col:1, col:8> col:8 implicit struct Redeclared +// CHECK-NEXT: | |-CXXMethodDecl [[ADDR_9:0x[a-z0-9]*]] <line:6:3, col:20> col:8 function 'void ()' implicit_instantiation implicit-inline instantiated_from [[ADDR_4]] +// CHECK-NEXT: | |-CXXConstructorDecl [[ADDR_10:0x[a-z0-9]*]] <line:5:8> col:8 implicit used constexpr Redeclared 'void () noexcept' inline default trivial +// CHECK-NEXT: | | `-CompoundStmt [[ADDR_11:0x[a-z0-9]*]] <col:8> +// CHECK-NEXT: | |-CXXConstructorDecl [[ADDR_12:0x[a-z0-9]*]] <col:8> col:8 implicit constexpr Redeclared 'void (const Redeclared<int> &)' inline default trivial noexcept-unevaluated [[ADDR_12]] +// CHECK-NEXT: | | `-ParmVarDecl [[ADDR_13:0x[a-z0-9]*]] <col:8> col:8 'const Redeclared<int> &' +// CHECK-NEXT: | `-CXXConstructorDecl [[ADDR_14:0x[a-z0-9]*]] <col:8> col:8 implicit constexpr Redeclared 'void (Redeclared<int> &&)' inline default trivial noexcept-unevaluated [[ADDR_14]] +// CHECK-NEXT: | `-ParmVarDecl [[ADDR_15:0x[a-z0-9]*]] <col:8> col:8 'Redeclared<int> &&' +// CHECK-NEXT: |-ClassTemplateDecl [[ADDR_16:0x[a-z0-9]*]] prev [[ADDR_0]] <line:9:1, line:10:8> col:8 Redeclared +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_17:0x[a-z0-9]*]] <line:9:11, col:17> col:17 class depth 0 index 0 T +// CHECK-NEXT: | |-CXXRecordDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_2]] <line:10:1, col:8> col:8 struct Redeclared +// CHECK-NEXT: | `-ClassTemplateSpecialization [[ADDR_19:0x[a-z0-9]*]] 'Redeclared' +// CHECK-NEXT: |-VarDecl [[ADDR_20:0x[a-z0-9]*]] <line:12:1, col:17> col:17 instantiation 'Redeclared<int>' callinit +// CHECK-NEXT: | `-CXXConstructExpr [[ADDR_21:0x[a-z0-9]*]] <col:17> 'Redeclared<int>' 'void () noexcept' +// CHECK-NEXT: |-FunctionTemplateDecl [[ADDR_22:0x[a-z0-9]*]] <line:14:1, line:17:1> line:15:6 redeclaredFunction +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_23:0x[a-z0-9]*]] <line:14:11, col:20> col:20 referenced typename depth 0 index 0 T +// CHECK-NEXT: | |-FunctionDecl [[ADDR_24:0x[a-z0-9]*]] <line:15:1, line:17:1> line:15:6 redeclaredFunction 'void (T)' +// CHECK-NEXT: | | |-ParmVarDecl [[ADDR_25:0x[a-z0-9]*]] <col:25, col:27> col:27 referenced t 'T' +// CHECK-NEXT: | | `-CompoundStmt [[ADDR_26:0x[a-z0-9]*]] <col:30, line:17:1> +// CHECK-NEXT: | | `-CStyleCastExpr [[ADDR_27:0x[a-z0-9]*]] <line:16:3, col:9> 'void' <ToVoid> +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_28:0x[a-z0-9]*]] <col:9> 'T' lvalue ParmVar [[ADDR_25]] 't' 'T' +// CHECK-NEXT: | `-FunctionDecl [[ADDR_29:0x[a-z0-9]*]] <line:15:1, line:17:1> line:15:6 used redeclaredFunction 'void (int)' implicit_instantiation +// CHECK-NEXT: | |-TemplateArgument type 'int' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_30:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-ParmVarDecl [[ADDR_31:0x[a-z0-9]*]] <line:20:25, col:27> col:27 used t 'int' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_32:0x[a-z0-9]*]] <line:15:30, line:17:1> +// CHECK-NEXT: | `-CStyleCastExpr [[ADDR_33:0x[a-z0-9]*]] <line:16:3, col:9> 'void' <ToVoid> +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_34:0x[a-z0-9]*]] <col:9> 'int' lvalue ParmVar [[ADDR_31]] 't' 'int' +// CHECK-NEXT: |-FunctionTemplateDecl [[ADDR_35:0x[a-z0-9]*]] prev [[ADDR_22]] <line:19:1, line:20:28> col:6 redeclaredFunction +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_36:0x[a-z0-9]*]] <line:19:11, col:20> col:20 referenced typename depth 0 index 0 T +// CHECK-NEXT: | |-FunctionDecl [[ADDR_37:0x[a-z0-9]*]] prev [[ADDR_24]] <line:20:1, col:28> col:6 redeclaredFunction 'void (T)' +// CHECK-NEXT: | | `-ParmVarDecl [[ADDR_38:0x[a-z0-9]*]] <col:25, col:27> col:27 t 'T' +// CHECK-NEXT: | `-Function [[ADDR_39:0x[a-z0-9]*]] 'redeclaredFunction' 'void (int)' +// CHECK-NEXT: `-FunctionDecl [[ADDR_40:0x[a-z0-9]*]] <line:22:1, line:24:1> line:22:6 instantiate 'void ()' +// CHECK-NEXT: `-CompoundStmt [[ADDR_41:0x[a-z0-9]*]] <col:20, line:24:1> +// CHECK-NEXT: `-CallExpr [[ADDR_42:0x[a-z0-9]*]] <line:23:3, col:23> 'void' +// CHECK-NEXT: |-ImplicitCastExpr [[ADDR_43:0x[a-z0-9]*]] <col:3> 'void (*)(int)' <FunctionToPointerDecay> +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_44:0x[a-z0-9]*]] <col:3> 'void (int)' lvalue Function [[ADDR_29]] 'redeclaredFunction' 'void (int)' (FunctionTemplate [[ADDR_35]] 'redeclaredFunction') +// CHECK-NEXT: `-IntegerLiteral [[ADDR_45:0x[a-z0-9]*]] <col:22> 'int' 0 `````````` </details> https://github.com/llvm/llvm-project/pull/156011 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
