From e28a6e5b22bab76297aae2cb68232e5efdd278c4 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 7 Apr 2017 16:26:53 -0400
Subject: [PATCH 06/10] FIMXE: WIP on C++ hints for filtered reserved words

---
 gcc/cp/name-lookup.c                              | 61 ++++++++++++++++++++++-
 gcc/testsuite/g++.dg/spellcheck-no-asm.C          |  7 +++
 gcc/testsuite/g++.dg/spellcheck-no-c++11.C        | 28 +++++++++++
 gcc/testsuite/g++.dg/spellcheck-no-concepts.C     | 10 ++++
 gcc/testsuite/g++.dg/spellcheck-no-gnu-keywords.C |  7 +++
 gcc/testsuite/g++.dg/spellcheck-no-tm.C           |  5 ++
 6 files changed, 117 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/spellcheck-no-asm.C
 create mode 100644 gcc/testsuite/g++.dg/spellcheck-no-c++11.C
 create mode 100644 gcc/testsuite/g++.dg/spellcheck-no-concepts.C
 create mode 100644 gcc/testsuite/g++.dg/spellcheck-no-gnu-keywords.C
 create mode 100644 gcc/testsuite/g++.dg/spellcheck-no-tm.C

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index c84023e..9028374 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -4951,6 +4951,48 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm,
     }
 }
 
+/* FIXME.  */
+
+class invalid_resword : public deferred_diagnostic
+{
+ public:
+  invalid_resword (location_t loc, tree name, const c_common_resword *resword)
+    : m_loc (loc), m_name (name), m_resword (resword)
+  {}
+
+  void emit ()
+  {
+    /* Try to supply the reason for the unavailable reserved word.
+       Compare to the logic in init_reswords.  */
+    if (cxx_dialect < cxx11 && (m_resword->disable & D_CXX11))
+      inform (m_loc,
+	      "%qE is only available as a reserved word from C++11 onwards",
+	      m_name);
+    /* FIXME
+  if (!flag_concepts)
+    mask |= D_CXX_CONCEPTS;
+  if (!flag_tm)
+    mask |= D_TRANSMEM;
+    */
+    else if (flag_no_asm && (m_resword->disable & (D_ASM | D_EXT)))
+      inform (m_loc, "%qE is not a reserved word due to %qs",
+	      m_name, "-fno-asm");
+    else if (flag_no_gnu_keywords && (m_resword->disable & D_EXT))
+      inform (m_loc, "%qE is not a reserved word due to %qs",
+	      m_name, "-fno-gnu-keywords"); // FIXME: test case
+    // FIXME: can we figure out why it's not available?
+    else
+      inform (m_loc, "%qE is not available due to compilation flags",
+	      m_name);
+  }
+
+ private:
+  location_t m_loc;
+  tree m_name;
+  const c_common_resword *m_resword;
+};
+
+
 /* Search for near-matches for NAME within the current bindings, and within
    macro names, returning the best match as a const char *, or NULL if
    no reasonable match is found.  */
@@ -5012,7 +5054,24 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind)
       /* Only consider reserved words that survived the
 	 filtering in init_reswords (e.g. for -std).  */
       if (!C_IS_RESERVED_WORD (resword_identifier))
-	continue;
+	{
+	  /* ...but if we're looking for a filtered reserved word,
+	     then report it as such.
+
+	     Various RID_* values are shared by different entries in
+	     c_common_reswords e.g.:
+	       { "__asm",               RID_ASM,        0 },
+	     vs:
+	       { "asm",                 RID_ASM,        D_ASM },
+	     Require an exact match with what the user supplied so
+	     that we can access the correct disable flags
+	     in invalid_resword::emit.  */
+	  if (resword_identifier == name)
+	    if (0 == strcmp (resword->word, IDENTIFIER_POINTER (name)))
+	      return name_hint (NULL, new invalid_resword (input_location,
+							   name, resword));
+	  continue;
+	}
 
       bm.consider (IDENTIFIER_POINTER (resword_identifier));
     }
diff --git a/gcc/testsuite/g++.dg/spellcheck-no-asm.C b/gcc/testsuite/g++.dg/spellcheck-no-asm.C
new file mode 100644
index 0000000..e8d0bfd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-no-asm.C
@@ -0,0 +1,7 @@
+// { dg-options "-fno-asm" }
+
+void test_asm (void)
+{
+  asm volatile("nop"); // { dg-error  "'asm' was not declared in this scope" }
+  // { dg-message "'asm' is not a reserved word due to '-fno-asm'" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-no-c++11.C b/gcc/testsuite/g++.dg/spellcheck-no-c++11.C
new file mode 100644
index 0000000..c5a8684
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-no-c++11.C
@@ -0,0 +1,28 @@
+// { dg-options "-std=c++98" }
+
+char16_t ch; // { dg-error  "'char16_t' does not name a type" }
+// { dg-message "'char16_t' is only available as a reserved word from C\\+\\+11 onwards" "" { target *-*-* } .-1 }
+
+char32_t ch; // { dg-error  "'char32_t' does not name a type" }
+// { dg-message "'char32_t' is only available as a reserved word from C\\+\\+11 onwards" "" { target *-*-* } .-1 }
+
+void test_static_assert (void)
+{
+  static_assert (1 == 0, "1 == 0"); // { dg-error  "'static_assert' was not declared in this scope" }
+  // { dg-message "'static_assert' is only available as a reserved word from C\\+\\+11 onwards" "" { target *-*-* } .-1 }
+}
+
+void *ptr = nullptr; // { dg-error  "'nullptr' was not declared in this scope" }
+// { dg-message "'nullptr' is only available as a reserved word from C\\+\\+11 onwards" "" { target *-*-* } .-1 }
+
+// FIXME:
+//thread_local int mine;
+
+#if 0
+  { "alignas",		RID_ALIGNAS,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "alignof",		RID_ALIGNOF,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "constexpr",	RID_CONSTEXPR,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "decltype",         RID_DECLTYPE,   D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "noexcept",		RID_NOEXCEPT,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+  { "thread_local",	RID_THREAD,	D_CXXONLY | D_CXX11 | D_CXXWARN },
+#endif
diff --git a/gcc/testsuite/g++.dg/spellcheck-no-concepts.C b/gcc/testsuite/g++.dg/spellcheck-no-concepts.C
new file mode 100644
index 0000000..19da4aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-no-concepts.C
@@ -0,0 +1,10 @@
+// { dg-options "-fno-concepts" }
+
+template <class T>
+concept bool EqualityComparable() { // { dg-error  "'concept' does not name a type" }
+  // { dg-message "'concept' only available with -fconcepts" "" { target *-*-* } .-1 }
+    return requires(T a, T b) {
+        {a == b} -> Boolean;
+        {a != b} -> Boolean;
+    };
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-no-gnu-keywords.C b/gcc/testsuite/g++.dg/spellcheck-no-gnu-keywords.C
new file mode 100644
index 0000000..367f247
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-no-gnu-keywords.C
@@ -0,0 +1,7 @@
+// { dg-options "-fno-gnu-keywords" }
+
+void test_typeof (int i)
+{
+  typeof(i) j; // { dg-error  "'typeof' was not declared in this scope" }
+  // { dg-message "'typeof' is not a reserved word due to '-fno-gnu-keywords'" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/g++.dg/spellcheck-no-tm.C b/gcc/testsuite/g++.dg/spellcheck-no-tm.C
new file mode 100644
index 0000000..b7027a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-no-tm.C
@@ -0,0 +1,5 @@
+int f()
+{
+  synchronized { } // { dg-error  "'synchronized' was not declared in this scope" }
+  // { dg-message "'synchronized' is not available due to compilation flags" "" { target *-*-* } .-1 }
+}
-- 
1.8.5.3

