Skip to content

Regression in libclang with template's default type parameters #585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
emilio opened this issue Mar 15, 2017 · 19 comments
Closed

Regression in libclang with template's default type parameters #585

emilio opened this issue Mar 15, 2017 · 19 comments

Comments

@emilio
Copy link
Contributor

emilio commented Mar 15, 2017

Using:

$ clang --version                                                                                                                                                                          
clang version 5.0.0 ([email protected]:llvm-mirror/clang 9d034c720c332a901de795c1528f6fbf437531a2) ([email protected]:llvm-mirror/llvm 5c49cf1beb13f4095a0fe1709d0da4ba310e13b1)
Target: x86_64-unknown-linux-gnu

cargo test generates the given diff compared with master:

diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs
index e5194c02..d9af9c11 100644
--- a/tests/expectations/tests/what_is_going_on.rs
+++ b/tests/expectations/tests/what_is_going_on.rs
@@ -29,4 +29,4 @@ pub struct PointTyped<F> {
 impl <F> Default for PointTyped<F> {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
-pub type IntPoint = PointTyped<f32>;
+pub type IntPoint = PointTyped;
@emilio
Copy link
Contributor Author

emilio commented Mar 15, 2017

cc @fitzgen

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

I just built with master llvm and clang and I'm getting even more failures:

---- header_issue_544_stylo_creduce_2_hpp stdout ----
	diff expected generated
--- expected: "/home/fitzgen/rust-bindgen/tests/expectations/tests/issue-544-stylo-creduce-2.rs"
+++ generated from: "/home/fitzgen/rust-bindgen/tests/headers/issue-544-stylo-creduce-2.hpp"
 /* automatically generated by rust-bindgen */
 
 
 #![allow(non_snake_case)]
 
 
 #[repr(C)]
 pub struct Foo {
-    pub member: Foo_SecondAlias,
+    pub member: Foo_Foo::SecondAlias,
 }
-pub type Foo_FirstAlias = [u8; 0usize];
-pub type Foo_SecondAlias = [u8; 0usize];
+pub type Foo_Foo::FirstAlias = [u8; 0usize];
+pub type Foo_Foo::SecondAlias = [u8; 0usize];
 impl Default for Foo {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
thread 'header_issue_544_stylo_creduce_2_hpp' panicked at 'Header and binding differ!', /home/fitzgen/rust-bindgen/target/debug/build/bindgen-fddff672ca36ebc4/out/tests.rs:97
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- header_issue_569_non_type_template_params_causing_layout_test_failures_hpp stdout ----
	diff expected generated
--- expected: "/home/fitzgen/rust-bindgen/tests/expectations/tests/issue-569-non-type-template-params-causing-layout-test-failures.rs"
+++ generated from: "/home/fitzgen/rust-bindgen/tests/headers/issue-569-non-type-template-params-causing-layout-test-failures.hpp"
 /* automatically generated by rust-bindgen */
 
 
 #![allow(non_snake_case)]
 
 
 pub const ENUM_VARIANT_1: _bindgen_ty_1 = _bindgen_ty_1::ENUM_VARIANT_1;
 pub const ENUM_VARIANT_2: _bindgen_ty_1 = _bindgen_ty_1::ENUM_VARIANT_2;
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum _bindgen_ty_1 { ENUM_VARIANT_1 = 0, ENUM_VARIANT_2 = 1, }
-pub type JS_Alias = u8;
+pub type JS_JS::Alias = u8;
 #[repr(C)]
 pub struct JS_Base {
-    pub f: JS_Alias,
+    pub f: JS_JS::Alias,
 }
 impl Default for JS_Base {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
 #[repr(C)]
 pub struct JS_AutoIdVector {
     pub _base: JS_Base,
 }
 #[test]
 fn bindgen_test_layout_JS_AutoIdVector() {
     assert_eq!(::std::mem::size_of::<JS_AutoIdVector>() , 1usize , concat ! (
                "Size of: " , stringify ! ( JS_AutoIdVector ) ));
     assert_eq! (::std::mem::align_of::<JS_AutoIdVector>() , 1usize , concat !
                 ( "Alignment of " , stringify ! ( JS_AutoIdVector ) ));
 }
 impl Default for JS_AutoIdVector {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
 #[test]
 fn __bindgen_test_layout_JS_Base_instantiation_20() {
     assert_eq!(::std::mem::size_of::<JS_Base>() , 1usize , concat ! (
                "Size of template specialization: " , stringify ! ( JS_Base )
                ));
     assert_eq!(::std::mem::align_of::<JS_Base>() , 1usize , concat ! (
                "Alignment of template specialization: " , stringify ! (
                JS_Base ) ));
 }
thread 'header_issue_569_non_type_template_params_causing_layout_test_failures_hpp' panicked at 'Header and binding differ!', /home/fitzgen/rust-bindgen/target/debug/build/bindgen-fddff672ca36ebc4/out/tests.rs:81

---- header_replace_template_alias_hpp stdout ----
	diff expected generated
--- expected: "/home/fitzgen/rust-bindgen/tests/expectations/tests/replace_template_alias.rs"
+++ generated from: "/home/fitzgen/rust-bindgen/tests/headers/replace_template_alias.hpp"
 /* automatically generated by rust-bindgen */
 
 
 #![allow(non_snake_case)]
 
 
-/// But the replacement type does use T!
-///
-/// <div rustbindgen replaces="JS::detail::MaybeWrapped" />
-pub type JS_detail_MaybeWrapped<T> = T;
+/// Notice how this doesn't use T.
+pub type JS_detail_JS::detail::MaybeWrapped = ::std::os::raw::c_int;
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
-pub struct JS_Rooted<T> {
-    pub ptr: JS_detail_MaybeWrapped<T>,
+pub struct JS_Rooted {
+    pub ptr: JS_detail_JS::detail::MaybeWrapped,
 }
-impl <T> Default for JS_Rooted<T> {
+impl Default for JS_Rooted {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
+/// But the replacement type does use T!
+///
+/// <div rustbindgen replaces="JS::detail::MaybeWrapped" />
+pub type JS_detail_MaybeWrapped<T> = T;
thread 'header_replace_template_alias_hpp' panicked at 'Header and binding differ!', /home/fitzgen/rust-bindgen/target/debug/build/bindgen-fddff672ca36ebc4/out/tests.rs:32

---- header_template_alias_hpp stdout ----
	diff expected generated
--- expected: "/home/fitzgen/rust-bindgen/tests/expectations/tests/template_alias.rs"
+++ generated from: "/home/fitzgen/rust-bindgen/tests/headers/template_alias.hpp"
 /* automatically generated by rust-bindgen */
 
 
 #![allow(non_snake_case)]
 
 
-pub type JS_detail_Wrapped<T> = T;
+pub type JS_detail_JS::detail::Wrapped<T> = T;
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
 pub struct JS_Rooted<T> {
-    pub ptr: JS_detail_Wrapped<T>,
+    pub ptr: JS_detail_JS::detail::Wrapped<T>,
 }
 impl <T> Default for JS_Rooted<T> {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
thread 'header_template_alias_hpp' panicked at 'Header and binding differ!', /home/fitzgen/rust-bindgen/target/debug/build/bindgen-fddff672ca36ebc4/out/tests.rs:52

---- header_template_alias_namespace_hpp stdout ----
	diff expected generated
--- expected: "/home/fitzgen/rust-bindgen/tests/expectations/tests/template_alias_namespace.rs"
+++ generated from: "/home/fitzgen/rust-bindgen/tests/headers/template_alias_namespace.hpp"
 /* automatically generated by rust-bindgen */
 
 
 #![allow(non_snake_case)]
 
 
 #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
 pub mod root {
     #[allow(unused_imports)]
     use self::super::root;
     pub mod JS {
         #[allow(unused_imports)]
         use self::super::super::root;
         pub mod detail {
             #[allow(unused_imports)]
             use self::super::super::super::root;
-            pub type Wrapped<T> = T;
+            pub type JS::detail::Wrapped<T> = T;
         }
         #[repr(C)]
         #[derive(Debug, Copy, Clone)]
         pub struct Rooted<T> {
-            pub ptr: root::JS::detail::Wrapped<T>,
+            pub ptr: root::JS::detail::JS::detail::Wrapped<T>,
         }
         impl <T> Default for Rooted<T> {
             fn default() -> Self { unsafe { ::std::mem::zeroed() } }
         }
     }
 }
thread 'header_template_alias_namespace_hpp' panicked at 'Header and binding differ!', /home/fitzgen/rust-bindgen/target/debug/build/bindgen-fddff672ca36ebc4/out/tests.rs:47

---- header_type_alias_template_specialized_hpp stdout ----
	thread 'header_type_alias_template_specialized_hpp' panicked at 'Should have found the template definition one way or another', /checkout/src/libcore/option.rs:785

---- header_what_is_going_on_hpp stdout ----
	diff expected generated
--- expected: "/home/fitzgen/rust-bindgen/tests/expectations/tests/what_is_going_on.rs"
+++ generated from: "/home/fitzgen/rust-bindgen/tests/headers/what_is_going_on.hpp"
 /* automatically generated by rust-bindgen */
 
 
 #![allow(non_snake_case)]
 
 
 #[repr(C)]
 #[derive(Debug, Default, Copy)]
 pub struct UnknownUnits {
     pub _address: u8,
 }
 #[test]
 fn bindgen_test_layout_UnknownUnits() {
     assert_eq!(::std::mem::size_of::<UnknownUnits>() , 1usize , concat ! (
                "Size of: " , stringify ! ( UnknownUnits ) ));
     assert_eq! (::std::mem::align_of::<UnknownUnits>() , 1usize , concat ! (
                 "Alignment of " , stringify ! ( UnknownUnits ) ));
 }
 impl Clone for UnknownUnits {
     fn clone(&self) -> Self { *self }
 }
 pub type Float = f32;
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
 pub struct PointTyped<F> {
     pub x: F,
     pub y: F,
 }
 impl <F> Default for PointTyped<F> {
     fn default() -> Self { unsafe { ::std::mem::zeroed() } }
 }
-pub type IntPoint = PointTyped<f32>;
+pub type IntPoint = PointTyped;
thread 'header_what_is_going_on_hpp' panicked at 'Header and binding differ!', /home/fitzgen/rust-bindgen/target/debug/build/bindgen-fddff672ca36ebc4/out/tests.rs:8


failures:
    header_issue_544_stylo_creduce_2_hpp
    header_issue_569_non_type_template_params_causing_layout_test_failures_hpp
    header_replace_template_alias_hpp
    header_template_alias_hpp
    header_template_alias_namespace_hpp
    header_type_alias_template_specialized_hpp
    header_what_is_going_on_hpp

test result: FAILED. 233 passed; 7 failed; 0 ignored; 0 measured

error: test failed

@emilio
Copy link
Contributor Author

emilio commented Mar 15, 2017

Well, most of them seem relatively easy to deal with, fortunately.

@emilio
Copy link
Contributor Author

emilio commented Mar 15, 2017

We should probably setup something in CI for this. For a while I was checking manually with llvm trunk, but...

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

So I've started investigating the what_is_going_on.hpp failure. I added edge labels in #587 and I got this super surprising result:

ir

We are parsing the template parameters as fields of the Comp... no idea what's up yet, still digging.

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

No nevermind... I just misinterpreted that graph.

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

We should probably setup something in CI for this. For a while I was checking manually with llvm trunk, but...

Yeah for sure. I don't think we want to block on llvm master failures, but we could run it with Travis's allow_failures set so we can at least see when issues are coming down the pipeline in a future release.

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

It looks like we are correctly determining that the units type parameter is not used, and shouldn't appear in the bindings.

And we are not finding the default value of the F type parameter, nor generating code for it in the bindings.

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

Here is the IR graph with libclang 3.9:

ir

Note that we have the default type for the F type parameter. I don't see (or remember seeing) any code for resolving default types for template type parameters, so I think libclang just stopped feeding us this information...

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

These aren't showing up in our cursor AST dumps, so we must be getting them from clang_{Cursor,Type}_getTemplateArgs.

@fitzgen
Copy link
Member

fitzgen commented Mar 15, 2017

Trying to figure out how to bisect llvm and clang in lockstep together...

@fitzgen
Copy link
Member

fitzgen commented Mar 16, 2017

Note to self: one can get a monorepo of clang + llvm for bisecting together here: http://llvm.org/docs/GettingStarted.html#for-developers-to-work-with-a-git-monorepo

@fitzgen
Copy link
Member

fitzgen commented Apr 4, 2017

It looks like although the template argumetns are no longer in the AST, they are in the canonical type. Here is a snippet from a clang AST dump:

     type.kind = Unexposed
     type.cconv = 100
     type.spelling = "Foo<bool>"
     type.number-of-template-args = 1
     type.is-variadic? false

     type.canonical.kind = Record
     type.canonical.cconv = 100
     type.canonical.spelling = "Foo<bool, int>"
     type.canonical.number-of-template-args = 2
     type.canonical.is-variadic? false

This is still an unhappy situation however because the types that we get out of clang::Cursor::template_args (which calls clang_Type_getTemplateArgumentAsType) don't have declarations, so we can't find the appropriate named template type item.

@fitzgen
Copy link
Member

fitzgen commented Apr 5, 2017

Bisected overnight, and it appears that this is the first commit where default template arguments stop appearing:

1cd3d77b9a8e18878a1654eb14053732b616b073 is the first bad commit
commit 1cd3d77b9a8e18878a1654eb14053732b616b073
Author: Argyrios Kyrtzidis <[email protected]>
Date:   Tue Nov 15 20:51:46 2016 +0000

    [libclang] Generalize clang_getNumTemplateArguments and clang_getTemplateArgumentAsType to other kind of specializations.
    
    Patch by Emilio Cobos Álvarez!
    https://reviews.llvm.org/D26663

@fitzgen
Copy link
Member

fitzgen commented Apr 5, 2017

I added logging to template instantiations and their type arguments + type arguments declaration cursor.

Before that commit, we hit this path for template instantiations, and we get the default type:

FITZGEN: TemplateInstantiation::from_ty
FITZGEN:     ty = Type(Foo<bool>, kind: Unexposed, cconv: 100, decl: Cursor(Foo kind: StructDecl, loc: ./tests/headers/default-template-parameter.hpp:2:8, usr: Some("c:@S@Foo>#b#I")), canon: Cursor(Foo kind: StructDecl, loc: ./tests/headers/default-template-parameter.hpp:2:8, usr: Some("c:@S@Foo>#b#I")))
                (
                 kind = StructDecl
                 spelling = "Foo"
                 location = ./tests/headers/default-template-parameter.hpp:2:8
                 is-definition? true
                 is-declaration? true
                 is-inlined-function? false
                 usr = "c:@S@Foo>#b#I"
                 number-of-template-args = 2

                 specialized.kind = ClassTemplate
                 specialized.spelling = "Foo"
                 specialized.location = ./tests/headers/default-template-parameter.hpp:2:8
                 specialized.is-definition? true
                 specialized.is-declaration? true
                 specialized.is-inlined-function? false
                 specialized.template-kind = StructDecl
                 specialized.usr = "c:@ST>2#T#T@Foo"

                 specialized.semantic-parent.kind = TranslationUnit
                 specialized.semantic-parent.spelling = "./tests/headers/default-template-parameter.hpp"
                 specialized.semantic-parent.location = builtin definitions
                 specialized.semantic-parent.is-definition? false
                 specialized.semantic-parent.is-declaration? false
                 specialized.semantic-parent.is-inlined-function? false

                 semantic-parent.kind = TranslationUnit
                 semantic-parent.spelling = "./tests/headers/default-template-parameter.hpp"
                 semantic-parent.location = builtin definitions
                 semantic-parent.is-definition? false
                 semantic-parent.is-declaration? false
                 semantic-parent.is-inlined-function? false

                 type.kind = Record
                 type.cconv = 100
                 type.spelling = "Foo<bool, int>"
                 type.number-of-template-args = 2
                 type.is-variadic? false
                )
FITZGEN:     template arg ty = Type(bool, kind: Bool, cconv: 100, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None))
                                (
                                 kind = NoDeclFound
                                 spelling = ""
                                 location = builtin definitions
                                 is-definition? false
                                 is-declaration? false
                                 is-inlined-function? false

                                 type.kind = Invalid
                                )
FITZGEN:     template arg ty = Type(int, kind: Int, cconv: 100, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None))
                                (
                                 kind = NoDeclFound
                                 spelling = ""
                                 location = builtin definitions
                                 is-definition? false
                                 is-declaration? false
                                 is-inlined-function? false

                                 type.kind = Invalid
                                )

After that commit, we don't get the type parameter's default type:

FITZGEN: TemplateInstantiation::from_ty
FITZGEN:     ty = Type(Foo<bool>, kind: Unexposed, cconv: 100, decl: Cursor(Foo kind: StructDecl, loc: ./tests/headers/default-template-parameter.hpp:2:8, usr: Some("c:@S@Foo>#b#I")), canon: Cursor(Foo kind: StructDecl, loc: ./tests/headers/default-template-parameter.hpp:2:8, usr: Some("c:@S@Foo>#b#I")))
                (
                 kind = StructDecl
                 spelling = "Foo"
                 location = ./tests/headers/default-template-parameter.hpp:2:8
                 is-definition? true
                 is-declaration? true
                 is-inlined-function? false
                 usr = "c:@S@Foo>#b#I"

                 specialized.kind = ClassTemplate
                 specialized.spelling = "Foo"
                 specialized.location = ./tests/headers/default-template-parameter.hpp:2:8
                 specialized.is-definition? true
                 specialized.is-declaration? true
                 specialized.is-inlined-function? false
                 specialized.template-kind = StructDecl
                 specialized.usr = "c:@ST>2#T#T@Foo"

                 specialized.semantic-parent.kind = TranslationUnit
                 specialized.semantic-parent.spelling = "./tests/headers/default-template-parameter.hpp"
                 specialized.semantic-parent.location = builtin definitions
                 specialized.semantic-parent.is-definition? false
                 specialized.semantic-parent.is-declaration? false
                 specialized.semantic-parent.is-inlined-function? false

                 semantic-parent.kind = TranslationUnit
                 semantic-parent.spelling = "./tests/headers/default-template-parameter.hpp"
                 semantic-parent.location = builtin definitions
                 semantic-parent.is-definition? false
                 semantic-parent.is-declaration? false
                 semantic-parent.is-inlined-function? false

                 type.kind = Record
                 type.cconv = 100
                 type.spelling = "Foo<bool, int>"
                 type.is-variadic? false
                )
FITZGEN:     template arg ty = Type(bool, kind: Bool, cconv: 100, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None))
                                (
                                 kind = NoDeclFound
                                 spelling = ""
                                 location = builtin definitions
                                 is-definition? false
                                 is-declaration? false
                                 is-inlined-function? false

                                 type.kind = Invalid
                                )

Here is a diff between the two logs:

--- /home/fitzgen/scratch/before.log	2017-04-05 10:47:42.317441781 -0700
+++ /home/fitzgen/scratch/after.log	2017-04-05 11:04:48.122808288 -0700
@@ -8,7 +8,6 @@
                  is-declaration? true
                  is-inlined-function? false
                  usr = "c:@S@Foo>#b#I"
-                 number-of-template-args = 2
 
                  specialized.kind = ClassTemplate
                  specialized.spelling = "Foo"
@@ -36,24 +35,12 @@
                  type.kind = Record
                  type.cconv = 100
                  type.spelling = "Foo<bool, int>"
-                 type.number-of-template-args = 2
                  type.is-variadic? false
                 )
 FITZGEN:     template arg ty = Type(bool, kind: Bool, cconv: 100, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None))
                                 (
                                  kind = NoDeclFound
                                  spelling = ""
-                                 location = builtin definitions
-                                 is-definition? false
-                                 is-declaration? false
-                                 is-inlined-function? false
-
-                                 type.kind = Invalid
-                                )
-FITZGEN:     template arg ty = Type(int, kind: Int, cconv: 100, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None))
-                                (
-                                 kind = NoDeclFound
-                                 spelling = ""
                                  location = builtin definitions
                                  is-definition? false
                                  is-declaration? false

In addition to losing the defautl type, we also lost information about the number of template arguments.

@emilio
Copy link
Contributor Author

emilio commented Apr 5, 2017

Note that that should be fixed by https://reviews.llvm.org/D26907, which re-added the path that made us lose the template argument count.

@fitzgen
Copy link
Member

fitzgen commented Apr 5, 2017

Upstream bug for tracking this regression: https://bugs.llvm.org/show_bug.cgi?id=32539

@fitzgen fitzgen changed the title Regression in recent clang version due to newest template changes. Regression in libclang with template's default type parameters Apr 5, 2017
@fitzgen
Copy link
Member

fitzgen commented Apr 5, 2017

Note that that should be fixed by https://reviews.llvm.org/D26907, which re-added the path that made us lose the template argument count.

Without the patch you shared in IRC, the llvm-project monorepo's master still has this regression and fails our regression test. Does master not have that patch you've linked, or is the statement that that patch should fix this regression false?

@emilio
Copy link
Contributor Author

emilio commented Apr 6, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants