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



Discussion:
I expect this is being caused because the `NestedMeta::Lit` case is not being treated as an error when it is encountered in the `AttributeArgs`.
Hmm, on inspection of the code I'm not sure why an error isn't being seen in this case. For example, the following code is triggered on the attribute args list being a string literal and returns an error:
https://github.com/TedDriggs/darling/blob/b71b23e59c9522dbb5b9408c3419d3ab000bbaf8/core/src/from_meta.rs#L130-L134
Maybe this block of generated code in the macro is the issue, since it ignores metas that are of the literal type:
https://github.com/TedDriggs/darling/blob/dbdcd93d0e78d3078f5fe148f7824fe1fe310368/core/src/codegen/variant_data.rs#L60-L68

I suspect the fix might be the following, however it is unclear to me what the ramifications if this code path has broader use:

```diff
  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 } 
          } 
+     } else {
+         // TODO: Error?
      }
  } 
```
@TedDriggs I've opened a fix for this issue in https://github.com/TedDriggs/darling/pull/193.
Just wanted to mention that I ran into this. I was trying to parse something like this:

```
#[derive(MyTrait)]
#[my_trait("foo")]
struct Foo {
}
``

Which was not working, but which wasn't throwing an error, I think because the literal "foo" was being ignored.



Patch:
diff --git a/core/src/codegen/variant_data.rs b/core/src/codegen/variant_data.rs
index c36a2638..b1f44504 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));
                     }
                 }
             }


Test patch:
diff --git a/tests/from_meta.rs b/tests/from_meta.rs
new file mode 100644
index 00000000..7523de36
--- /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()
+    );
+}