diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index a9be8df0384..b2ad991008a 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -39,6 +39,10 @@ along with GCC; see the file COPYING3.  If not see
   do { warning (OPT_Wpragmas, gmsgid); return; } while (0)
 #define GCC_BAD2(gmsgid, arg) \
   do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0)
+#define GCC_BAD_AT(loc, gmsgid)					\
+  do { warning_at (loc, OPT_Wpragmas, gmsgid); return; } while (0)
+#define GCC_BAD2_AT(loc, gmsgid, arg)			\
+  do { warning_at (loc, OPT_Wpragmas, gmsgid, arg); return; } while (0)
 
 struct GTY(()) align_stack {
   int		       alignment;
@@ -130,6 +134,7 @@ pop_alignment (tree id)
 static void
 handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
 {
+  location_t loc;
   tree x, id = 0;
   int align = -1;
   enum cpp_ttype token;
@@ -138,7 +143,7 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
   if (pragma_lex (&x) != CPP_OPEN_PAREN)
     GCC_BAD ("missing %<(%> after %<#pragma pack%> - ignored");
 
-  token = pragma_lex (&x);
+  token = pragma_lex (&x, &loc);
   if (token == CPP_CLOSE_PAREN)
     {
       action = set;
@@ -147,7 +152,7 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
   else if (token == CPP_NUMBER)
     {
       if (TREE_CODE (x) != INTEGER_CST)
-	GCC_BAD ("invalid constant in %<#pragma pack%> - ignored");
+	GCC_BAD_AT (loc, "invalid constant in %<#pragma pack%> - ignored");
       align = TREE_INT_CST_LOW (x);
       action = set;
       if (pragma_lex (&x) != CPP_CLOSE_PAREN)
@@ -167,11 +172,12 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
       else if (!strcmp (op, "pop"))
 	action = pop;
       else
-	GCC_BAD2 ("unknown action %qE for %<#pragma pack%> - ignored", x);
+	GCC_BAD2_AT (loc, "unknown action %qE for %<#pragma pack%> - ignored",
+		     x);
 
       while ((token = pragma_lex (&x)) == CPP_COMMA)
 	{
-	  token = pragma_lex (&x);
+	  token = pragma_lex (&x, &loc);
 	  if (token == CPP_NAME && id == 0)
 	    {
 	      id = x;
@@ -179,7 +185,8 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
 	  else if (token == CPP_NUMBER && action == push && align == -1)
 	    {
 	      if (TREE_CODE (x) != INTEGER_CST)
-		GCC_BAD ("invalid constant in %<#pragma pack%> - ignored");
+		GCC_BAD_AT (loc,
+			    "invalid constant in %<#pragma pack%> - ignored");
 	      align = TREE_INT_CST_LOW (x);
 	      if (align == -1)
 		action = set;
@@ -195,8 +202,8 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
   else
     GCC_BAD ("malformed %<#pragma pack%> - ignored");
 
-  if (pragma_lex (&x) != CPP_EOF)
-    warning (OPT_Wpragmas, "junk at end of %<#pragma pack%>");
+  if (pragma_lex (&x, &loc) != CPP_EOF)
+    warning_at (loc, OPT_Wpragmas, "junk at end of %<#pragma pack%>");
 
   if (flag_pack_struct)
     GCC_BAD ("%<#pragma pack%> has no effect with %<-fpack-struct%> - ignored");
@@ -857,6 +864,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
 static void
 handle_pragma_target(cpp_reader *ARG_UNUSED(dummy))
 {
+  location_t loc;
   enum cpp_ttype token;
   tree x;
   bool close_paren_needed_p = false;
@@ -867,16 +875,16 @@ handle_pragma_target(cpp_reader *ARG_UNUSED(dummy))
       return;
     }
 
-  token = pragma_lex (&x);
+  token = pragma_lex (&x, &loc);
   if (token == CPP_OPEN_PAREN)
     {
       close_paren_needed_p = true;
-      token = pragma_lex (&x);
+      token = pragma_lex (&x, &loc);
     }
 
   if (token != CPP_STRING)
     {
-      GCC_BAD ("%<#pragma GCC option%> is not a string");
+      GCC_BAD_AT (loc, "%<#pragma GCC option%> is not a string");
       return;
     }
 
@@ -1149,6 +1157,7 @@ handle_pragma_reset_options (cpp_reader *ARG_UNUSED(dummy))
 static void
 handle_pragma_message (cpp_reader *ARG_UNUSED(dummy))
 {
+  location_t loc;
   enum cpp_ttype token;
   tree x, message = 0;
 
@@ -1170,8 +1179,8 @@ handle_pragma_message (cpp_reader *ARG_UNUSED(dummy))
 
   gcc_assert (message);
 
-  if (pragma_lex (&x) != CPP_EOF)
-    warning (OPT_Wpragmas, "junk at end of %<#pragma message%>");
+  if (pragma_lex (&x, &loc) != CPP_EOF)
+    warning_at (loc, OPT_Wpragmas, "junk at end of %<#pragma message%>");
 
   if (TREE_STRING_LENGTH (message) > 1)
     inform (input_location, "%<#pragma message: %s%>",
diff --git a/gcc/testsuite/gcc.dg/bad-pragma-locations.c b/gcc/testsuite/gcc.dg/bad-pragma-locations.c
new file mode 100644
index 00000000000..8068839881d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bad-pragma-locations.c
@@ -0,0 +1,86 @@
+/* Verify that we use precise locations when emitting diagnostics
+   about pragmas.  */
+
+/* { dg-do assemble } */
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+/* pack ****************************************************************************/
+
+#pragma pack
+/* { dg-warning "missing '\\(' after '#pragma pack' - ignored" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack
+         ^~~~
+   { dg-end-multiline-output "" }  */
+
+#pragma pack (
+/* { dg-warning "malformed '#pragma pack' - ignored" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack (
+         ^~~~
+   { dg-end-multiline-output "" }  */
+
+#pragma pack (32
+/* { dg-warning "malformed '#pragma pack' - ignored" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack (32
+         ^~~~
+   { dg-end-multiline-output "" }  */
+
+#pragma pack (3.14159
+/* { dg-warning "invalid constant in '#pragma pack' - ignored" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack (3.14159
+               ^~~~~~~
+   { dg-end-multiline-output "" }  */
+
+#pragma pack (push, 3.14159
+/* { dg-warning "invalid constant in '#pragma pack' - ignored" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack (push, 3.14159
+                     ^~~~~~~
+   { dg-end-multiline-output "" }  */
+
+#pragma pack (toothbrush
+/* { dg-warning "unknown action 'toothbrush' for '#pragma pack' - ignored" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack (toothbrush
+               ^~~~~~~~~~
+   { dg-end-multiline-output "" }  */
+
+#pragma pack() pyjamas
+/* { dg-warning "junk at end of '#pragma pack'" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma pack() pyjamas
+                ^~~~~~~
+   { dg-end-multiline-output "" }  */
+
+/* target ****************************************************************************/
+
+#pragma GCC target 42
+/* { dg-warning "#pragma GCC option' is not a string" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma GCC target 42
+                    ^~
+   { dg-end-multiline-output "" }  */
+
+#pragma GCC target ( 1776
+/* { dg-warning "#pragma GCC option' is not a string" "" { target *-*-* } .-1 }
+   { dg-begin-multiline-output "" }
+ #pragma GCC target ( 1776
+                      ^~~~
+   { dg-end-multiline-output "" }  */
+
+/* message ****************************************************************************/
+
+#pragma message "foo" int
+/* { dg-warning "junk at end of '#pragma message'" "" { target *-*-* } .-1 }
+   { dg-message "'#pragma message: foo'" "" { target *-*-* } .-2 }
+   { dg-begin-multiline-output "" }
+ #pragma message "foo" int
+                       ^~~
+   { dg-end-multiline-output "" }
+   { dg-begin-multiline-output "" }
+ #pragma message "foo" int
+         ^~~~~~~
+   { dg-end-multiline-output "" }  */
