diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 191863e491..ffd9f4d699 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2019-02-14  Leszek Swirski  <leszeks@google.com>
+
+	* amd64-tdep.c (amd64_classify_aggregate): Use cp_pass_by_reference
+	rather than a hand-rolled POD check when checking for forced MEMORY
+	classification.
+
 2019-02-12  John Baldwin  <jhb@FreeBSD.org>
 
 	* symfile.c (find_separate_debug_file): Use canonical path of
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 3f61997d66..d32638a20a 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -541,17 +541,40 @@ amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
 
 static void amd64_classify (struct type *type, enum amd64_reg_class theclass[2]);
 
-/* Return non-zero if TYPE is a non-POD structure or union type.  */
+/* Return true if TYPE is a structure or union with unaligned fields.  */
 
-static int
-amd64_non_pod_p (struct type *type)
+static bool
+amd64_has_unaligned_fields (struct type *type)
 {
-  /* ??? A class with a base class certainly isn't POD, but does this
-     catch all non-POD structure types?  */
-  if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_N_BASECLASSES (type) > 0)
-    return 1;
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+      || TYPE_CODE (type) == TYPE_CODE_UNION)
+    {
+      for (int i = 0; i < TYPE_NFIELDS (type); i++)
+	{
+	  struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+	  int bitpos = TYPE_FIELD_BITPOS (type, i);
+	  int align = type_align(subtype);
 
-  return 0;
+	  /* Ignore static fields, or empty fields, for example nested
+	     empty structures.  */
+	  if (field_is_static (&TYPE_FIELD (type, i))
+	      || (TYPE_FIELD_BITSIZE (type, i) == 0
+		  && TYPE_LENGTH (subtype) == 0))
+	    continue;
+
+	  if (bitpos % 8 != 0)
+	    return true;
+
+	  int bytepos = bitpos / 8;
+	  if (bytepos % align != 0)
+	    return true;
+
+	  if (amd64_has_unaligned_fields(subtype))
+	    return true;
+	}
+    }
+
+  return false;
 }
 
 /* Classify TYPE according to the rules for aggregate (structures and
@@ -560,10 +583,9 @@ amd64_non_pod_p (struct type *type)
 static void
 amd64_classify_aggregate (struct type *type, enum amd64_reg_class theclass[2])
 {
-  /* 1. If the size of an object is larger than two eightbytes, or in
-        C++, is a non-POD structure or union type, or contains
+  /* 1. If the size of an object is larger than two eightbytes, or it has
         unaligned fields, it has class memory.  */
-  if (TYPE_LENGTH (type) > 16 || amd64_non_pod_p (type))
+  if (TYPE_LENGTH (type) > 16 || amd64_has_unaligned_fields (type))
     {
       theclass[0] = theclass[1] = AMD64_MEMORY;
       return;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 1ee4f1bd9b..5fa2b6ef7b 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2019-02-14  Leszek Swirski  <leszeks@google.com>
+
+	* gdb.arch/amd64-eval.cc: New file.
+	* gdb.arch/amd64-eval.exp: New file.
+
 2019-02-12  Weimin Pan  <weimin.pan@oracle.com>
 
 	PR breakpoints/21870
diff --git a/gdb/testsuite/gdb.arch/amd64-eval.cc b/gdb/testsuite/gdb.arch/amd64-eval.cc
new file mode 100644
index 0000000000..a986a49db3
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-eval.cc
@@ -0,0 +1,120 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cassert>
+
+/* A simple structure with a single integer field. Should be returned in
+   a register.  */
+struct SimpleBase
+{
+  SimpleBase (int32_t x) : x (x) {}
+
+  int32_t x;
+};
+
+/* A simple structure derived from the simple base. Should be returned in
+   a register.  */
+struct SimpleDerived : public SimpleBase
+{
+  SimpleDerived (int32_t x) : SimpleBase (x) {}
+};
+
+/* A structure derived from the simple base with a non-trivial destructor.
+   Should be returned on the stack.  */
+struct NonTrivialDestructorDerived : public SimpleBase
+{
+  NonTrivialDestructorDerived (int32_t x) : SimpleBase (x) {}
+  ~NonTrivialDestructorDerived() { x = 1; }
+};
+
+/* A structure with unaligned fields. Should be returned on the stack.  */
+struct UnalignedFields
+{
+  UnalignedFields (int32_t x, double y) : x (x), y (y) {}
+
+  int32_t x;
+  double y;
+} __attribute__((packed));
+
+/* A structure with unaligned fields in its base class. Should be
+   returned on the stack.  */
+struct UnalignedFieldsInBase : public UnalignedFields
+{
+  UnalignedFieldsInBase (int32_t x, double y, int32_t x2)
+  : UnalignedFields (x, y), x2 (x2) {}
+
+  int32_t x2;
+};
+
+class Foo
+{
+public:
+  SimpleBase
+  return_simple_base (int32_t x)
+  {
+    assert (this->tag == EXPECTED_TAG);
+    return SimpleBase (x);
+  }
+
+  SimpleDerived
+  return_simple_derived (int32_t x)
+  {
+    assert (this->tag == EXPECTED_TAG);
+    return SimpleDerived (x);
+  }
+
+  NonTrivialDestructorDerived
+  return_non_trivial_destructor (int32_t x)
+  {
+    assert (this->tag == EXPECTED_TAG);
+    return NonTrivialDestructorDerived (x);
+  }
+
+  UnalignedFields
+  return_unaligned (int32_t x, double y)
+  {
+    assert (this->tag == EXPECTED_TAG);
+    return UnalignedFields (x, y);
+  }
+
+  UnalignedFieldsInBase
+  return_unaligned_in_base (int32_t x, double y, int32_t x2)
+  {
+    assert (this->tag == EXPECTED_TAG);
+    return UnalignedFieldsInBase (x, y, x2);
+  }
+
+private:
+  /* Use a tag to detect if the "this" value is correct.  */
+  static const int EXPECTED_TAG = 0xF00F00F0;
+  int tag = EXPECTED_TAG;
+};
+
+int
+main (int argc, char *argv[])
+{
+  Foo foo;
+  foo.return_simple_base(1);
+  foo.return_simple_derived(2);
+  foo.return_non_trivial_destructor(3);
+  foo.return_unaligned(4, 5);
+  foo.return_unaligned_in_base(6, 7, 8);
+  return 0;  // break-here
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-eval.exp b/gdb/testsuite/gdb.arch/amd64-eval.exp
new file mode 100644
index 0000000000..c33777d2b4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-eval.exp
@@ -0,0 +1,43 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This testcase exercises evaluation with amd64 calling conventions.
+
+standard_testfile .cc
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
+	  { debug c++ }] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "call foo.return_simple_base(12)" \
+    " = {x = 12}"
+gdb_test "call foo.return_simple_derived(34)" \
+    " = {<SimpleBase> = {x = 34}, <No data fields>}"
+gdb_test "call foo.return_non_trivial_destructor(56)" \
+    " = {<SimpleBase> = {x = 56}, <No data fields>}"
+gdb_test "call foo.return_unaligned(78, 9.25)" \
+    " = {x = 78, y = 9.25}"
+gdb_test "call foo.return_unaligned_in_base(23, 4.5, 67)" \
+    " = {<UnalignedFields> = {x = 23, y = 4.5}, x2 = 67}"
