Repository: TedDriggs/darling (rust)

Issue:
FromMeta parsing doesn't error on unrecognized literals in attribute list
FromMeta doesn't error in all cases that unexpected tokens end up in the attribute list.

It doesn't error in the case that a string literal is in the attribute list. For example:
```rust
#[myattribute(myfield = "export", "randomliteral")]
```

Parsing the attribute list will error if it sees a field that is anticipated, but not for `"randomliteral"` which it will ignore.

cc @jonjove


Pull request description:
Error when parsing FromMeta containing NestedMeta::Lit
### What
Generate an error when parsing derived `FromMeta` implementations that contain a `NestedMeta::Lit`.

### Why
Literal values are unsupported in the code generated by `FromMeta`. Literal values, like strings, get ignored by the parse implementation that gets generated with the FromMeta generated code. This is confusing to a user since it appears like the value is being accepted and used in some way. We should error when the user provides a literal since the derived code will do nothing with it.

Fix #192

Patch:
diff --git a/core/src/codegen/variant_data.rs b/core/src/codegen/variant_data.rs
index c36a263..b1f4450 100644
--- a/core/src/codegen/variant_data.rs
+++ b/core/src/codegen/variant_data.rs
@@ -58,11 +58,17 @@ impl<'a> FieldsGen<'a> {
 
         quote!(
             for __item in __items {
-                if let ::syn::NestedMeta::Meta(ref __inner) = *__item {
-                    let __name = ::darling::util::path_to_string(__inner.path());
-                    match __name.as_str() {
-                        #(#arms)*
-                        __other => { #handle_unknown }
+                match *__item {
+                    ::syn::NestedMeta::Meta(ref __inner) => {
+                        let __name = ::darling::util::path_to_string(__inner.path());
+                        match __name.as_str() {
+                            #(#arms)*
+                            __other => { #handle_unknown }
+                        }
+                    }
+                    ::syn::NestedMeta::Lit(ref __inner) => {
+                        __errors.push(::darling::Error::unsupported_format("literal")
+                            .with_span(__inner));
                     }
                 }
             }
diff --git a/core/src/error/mod.rs b/core/src/error/mod.rs
index ca68956..87dbdff 100644
--- a/core/src/error/mod.rs
+++ b/core/src/error/mod.rs
@@ -683,10 +683,14 @@ impl Extend<Error> for Accumulator {
 
 impl Drop for Accumulator {
     fn drop(&mut self) {
-        if let Some(errors) = &mut self.0 {
-            match errors.len() {
-                0 => panic!("darling::error::Accumulator dropped without being finished"),
-                error_count => panic!("darling::error::Accumulator dropped without being finished. {} errors were lost.", error_count)
+        // don't try to panic if we are currently unwinding a panic
+        // otherwise we end up with an unhelful "thread panicked while panicking. aborting." message
+        if !std::thread::panicking() {
+            if let Some(errors) = &mut self.0 {
+                match errors.len() {
+                    0 => panic!("darling::error::Accumulator dropped without being finished"),
+                    error_count => panic!("darling::error::Accumulator dropped without being finished. {} errors were lost.", error_count)
+                }
             }
         }
     }


Test patch:
diff --git a/tests/from_meta.rs b/tests/from_meta.rs
new file mode 100644
index 0000000..7523de3
--- /dev/null
+++ b/tests/from_meta.rs
@@ -0,0 +1,66 @@
+use darling::{Error, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, FromMeta)]
+struct Meta {
+    #[darling(default)]
+    meta1: Option<String>,
+    #[darling(default)]
+    meta2: bool,
+}
+
+#[test]
+fn nested_meta_meta_value() {
+    let meta = Meta::from_list(&vec![parse_quote! {
+        meta1 = "thefeature"
+    }])
+    .unwrap();
+    assert_eq!(meta.meta1, Some("thefeature".to_string()));
+    assert_eq!(meta.meta2, false);
+}
+
+#[test]
+fn nested_meta_meta_bool() {
+    let meta = Meta::from_list(&vec![parse_quote! {
+        meta2
+    }])
+    .unwrap();
+    assert_eq!(meta.meta1, None);
+    assert_eq!(meta.meta2, true);
+}
+
+#[test]
+fn nested_meta_lit_string_errors() {
+    let err = Meta::from_list(&vec![parse_quote! {
+        "meta2"
+    }])
+    .unwrap_err();
+    assert_eq!(
+        err.to_string(),
+        Error::unsupported_format("literal").to_string()
+    );
+}
+
+#[test]
+fn nested_meta_lit_integer_errors() {
+    let err = Meta::from_list(&vec![parse_quote! {
+        2
+    }])
+    .unwrap_err();
+    assert_eq!(
+        err.to_string(),
+        Error::unsupported_format("literal").to_string()
+    );
+}
+
+#[test]
+fn nested_meta_lit_bool_errors() {
+    let err = Meta::from_list(&vec![parse_quote! {
+        true
+    }])
+    .unwrap_err();
+    assert_eq!(
+        err.to_string(),
+        Error::unsupported_format("literal").to_string()
+    );
+}