From 982b4ced7d65202dfd9639c06048d13bc26e949c Mon Sep 17 00:00:00 2001
From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Mon, 1 Jul 2019 20:54:14 +0000
Subject: [PATCH] Replace all ASSERT_*() macros with STATIC_ASSERT().
 static_assert.h: New file with STATIC_ASSERT() macro using C++11
 static_assert() if available. Makefile.am, os_win32/vc14/smart*.vcxproj*: Add
 new file.

git-svn-id: https://svn.code.sf.net/p/smartmontools/code/trunk@4934 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 smartmontools/ChangeLog                       |  5 ++
 smartmontools/Makefile.am                     |  2 +
 smartmontools/atacmdnames.cpp                 | 11 +--
 smartmontools/atacmds.h                       | 65 ++++++--------
 smartmontools/dev_intelliprop.cpp             |  6 +-
 smartmontools/nvmecmds.cpp                    | 13 +--
 smartmontools/nvmecmds.h                      | 12 ++-
 smartmontools/os_win32.cpp                    | 89 ++++++++-----------
 smartmontools/os_win32/vc14/smartctl.vcxproj  |  1 +
 .../os_win32/vc14/smartctl.vcxproj.filters    |  1 +
 smartmontools/os_win32/vc14/smartd.vcxproj    |  1 +
 .../os_win32/vc14/smartd.vcxproj.filters      |  1 +
 smartmontools/static_assert.h                 | 27 ++++++
 13 files changed, 126 insertions(+), 108 deletions(-)
 create mode 100644 smartmontools/static_assert.h

diff --git a/smartmontools/ChangeLog b/smartmontools/ChangeLog
index cd432f29d..53351d2c0 100644
--- a/smartmontools/ChangeLog
+++ b/smartmontools/ChangeLog
@@ -2,6 +2,11 @@ $Id$
 
 2019-07-01  Christian Franke  <franke@computer.org>
 
+	Replace all ASSERT_*() macros with STATIC_ASSERT().
+	static_assert.h: New file with STATIC_ASSERT() macro using C++11
+	static_assert() if available.
+	Makefile.am, os_win32/vc14/smart*.vcxproj*: Add new file.
+
 	os_win32/vc14/smart*.vcxproj*: Add missing scsinvme.cpp.
 
 2019-06-28  Christian Franke  <franke@computer.org>
diff --git a/smartmontools/Makefile.am b/smartmontools/Makefile.am
index 40051aed7..1cfdff796 100644
--- a/smartmontools/Makefile.am
+++ b/smartmontools/Makefile.am
@@ -83,6 +83,7 @@ smartctl_SOURCES = \
         scsinvme.cpp \
         scsiprint.cpp \
         scsiprint.h \
+        static_assert.h \
         utility.cpp \
         utility.h \
         sg_unaligned.h
@@ -154,6 +155,7 @@ smartd_SOURCES = \
         scsicmds.h \
         scsiata.cpp \
         scsinvme.cpp \
+        static_assert.h \
         utility.cpp \
         utility.h \
         sg_unaligned.h
diff --git a/smartmontools/atacmdnames.cpp b/smartmontools/atacmdnames.cpp
index 073fb22f1..3fe5b847a 100644
--- a/smartmontools/atacmdnames.cpp
+++ b/smartmontools/atacmdnames.cpp
@@ -1,15 +1,17 @@
 /*
  * atacmdnames.cpp
  *
- * Home page of code is: http://www.smartmontools.org
+ * Home page of code is: https://www.smartmontools.org
  *
- * Copyright (C) 2003-8 Philip Williams
- * Copyright (C) 2012 Christian Franke
+ * Copyright (C) 2003-08 Philip Williams
+ * Copyright (C) 2012-19 Christian Franke
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include "atacmdnames.h"
+#include "static_assert.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 
@@ -301,8 +303,7 @@ const char * const command_table[] = {
   cmd_vendor_specific
 };
 
-typedef char ASSERT_command_table_size[
-  sizeof(command_table)/sizeof(command_table[0]) == 256 ? 1 : -1];
+STATIC_ASSERT(sizeof(command_table) == 256 * sizeof(command_table[0]));
 
 /* Returns the name of the command (and possibly sub-command) with the given
    command code and feature register values.   For most command codes this
diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h
index 71e37b285..94c9ae9ba 100644
--- a/smartmontools/atacmds.h
+++ b/smartmontools/atacmds.h
@@ -1,10 +1,10 @@
 /*
  * atacmds.h
  *
- * Home page of code is: http://www.smartmontools.org
+ * Home page of code is: https://www.smartmontools.org
  *
  * Copyright (C) 2002-11 Bruce Allen
- * Copyright (C) 2008-17 Christian Franke
+ * Copyright (C) 2008-19 Christian Franke
  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,14 +16,7 @@
 #define ATACMDS_H_CVSID "$Id$"
 
 #include "dev_interface.h" // ata_device
-
-// Macro to check expected size of struct at compile time using a
-// dummy typedef.  On size mismatch, compiler reports a negative array
-// size.  If you see an error message of this form, it means that the
-// #pragma pack(1) pragma below is not having the desired effect on
-// your compiler.
-#define ASSERT_SIZEOF_STRUCT(s, n) \
-  typedef char assert_sizeof_struct_##s[(sizeof(struct s) == (n)) ? 1 : -1]
+#include "static_assert.h"
 
 // Add __attribute__((packed)) if compiler supports it
 // because some gcc versions (at least ARM) lack support of #pragma pack()
@@ -137,7 +130,7 @@ struct ata_identify_device {
   unsigned short words088_255[168];
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_identify_device, 512);
+STATIC_ASSERT(sizeof(ata_identify_device) == 512);
 
 /* ata_smart_attribute is the vendor specific in SFF-8035 spec */ 
 #pragma pack(1)
@@ -152,7 +145,7 @@ struct ata_smart_attribute {
   unsigned char reserv;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_attribute, 12);
+STATIC_ASSERT(sizeof(ata_smart_attribute) == 12);
 
 // MACROS to interpret the flags bits in the previous structure.
 // These have not been implemented using bitflags and a union, to make
@@ -222,7 +215,7 @@ struct ata_smart_values {
   unsigned char chksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_values, 512);
+STATIC_ASSERT(sizeof(ata_smart_values) == 512);
 
 /* Maxtor, IBM: self-test failure checkpoint byte meaning:
  00 - write test
@@ -241,7 +234,7 @@ struct ata_smart_threshold_entry {
   unsigned char reserved[10];
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_threshold_entry, 12);
+STATIC_ASSERT(sizeof(ata_smart_threshold_entry) == 12);
 
 /* Format of Read SMART THreshold Command */
 /* Compare to ata_smart_values above */
@@ -253,7 +246,7 @@ struct ata_smart_thresholds_pvt {
   unsigned char chksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_thresholds_pvt, 512);
+STATIC_ASSERT(sizeof(ata_smart_thresholds_pvt) == 512);
 
 
 // Table 42 of T13/1321D Rev 1 spec (Error Data Structure)
@@ -272,7 +265,7 @@ struct ata_smart_errorlog_error_struct {
   unsigned short timestamp;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_error_struct, 30);
+STATIC_ASSERT(sizeof(ata_smart_errorlog_error_struct) == 30);
 
 
 // Table 41 of T13/1321D Rev 1 spec (Command Data Structure)
@@ -289,7 +282,7 @@ struct ata_smart_errorlog_command_struct {
   unsigned int timestamp;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_command_struct, 12);
+STATIC_ASSERT(sizeof(ata_smart_errorlog_command_struct) == 12);
 
 // Table 40 of T13/1321D Rev 1 spec (Error log data structure)
 #pragma pack(1)
@@ -298,7 +291,7 @@ struct ata_smart_errorlog_struct {
   struct ata_smart_errorlog_error_struct error_struct;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_struct, 90);
+STATIC_ASSERT(sizeof(ata_smart_errorlog_struct) == 90);
 
 // Table 39 of T13/1321D Rev 1 spec (SMART error log sector)
 #pragma pack(1)
@@ -311,7 +304,7 @@ struct ata_smart_errorlog {
   unsigned char checksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_errorlog, 512);
+STATIC_ASSERT(sizeof(ata_smart_errorlog) == 512);
 
 
 // Extended Comprehensive SMART Error Log data structures
@@ -342,7 +335,7 @@ struct ata_smart_exterrlog_command
   unsigned int timestamp;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog_command, 18);
+STATIC_ASSERT(sizeof(ata_smart_exterrlog_command) == 18);
 
 // Error data structure
 // Table A.10 T13/1699-D Revision 6a
@@ -367,7 +360,7 @@ struct ata_smart_exterrlog_error
   unsigned short timestamp;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog_error, 34);
+STATIC_ASSERT(sizeof(ata_smart_exterrlog_error) == 34);
 
 // Error log data structure
 // Table A.8 of T13/1699-D Revision 6a
@@ -378,7 +371,7 @@ struct ata_smart_exterrlog_error_log
   ata_smart_exterrlog_error error;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog_error_log, 124);
+STATIC_ASSERT(sizeof(ata_smart_exterrlog_error_log) == 124);
 
 // Ext. Comprehensive SMART error log
 // Table A.7 of T13/1699-D Revision 6a
@@ -394,7 +387,7 @@ struct ata_smart_exterrlog
   unsigned char checksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog, 512);
+STATIC_ASSERT(sizeof(ata_smart_exterrlog) == 512);
 
 
 // Table 45 of T13/1321D Rev 1 spec (Self-test log descriptor entry)
@@ -408,7 +401,7 @@ struct ata_smart_selftestlog_struct {
   unsigned char vendorspecific[15];
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_selftestlog_struct, 24);
+STATIC_ASSERT(sizeof(ata_smart_selftestlog_struct) == 24);
 
 // Table 44 of T13/1321D Rev 1 spec (Self-test log data structure)
 #pragma pack(1)
@@ -421,7 +414,7 @@ struct ata_smart_selftestlog {
   unsigned char chksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_selftestlog, 512);
+STATIC_ASSERT(sizeof(ata_smart_selftestlog) == 512);
 
 // Extended SMART Self-test log data structures
 // See Section A.8 of
@@ -441,7 +434,7 @@ struct ata_smart_extselftestlog_desc
   unsigned char vendorspecific[15];
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_extselftestlog_desc, 26);
+STATIC_ASSERT(sizeof(ata_smart_extselftestlog_desc) == 26);
 
 // Extended Self-test log data structure
 // Table A.12 of T13/1699-D Revision 6a
@@ -457,7 +450,7 @@ struct ata_smart_extselftestlog
   unsigned char chksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_extselftestlog, 512);
+STATIC_ASSERT(sizeof(ata_smart_extselftestlog) == 512);
 
 // SMART LOG DIRECTORY Table 52 of T13/1532D Vol 1 Rev 1a
 #pragma pack(1)
@@ -466,7 +459,7 @@ struct ata_smart_log_entry {
   unsigned char reserved;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_log_entry, 2);
+STATIC_ASSERT(sizeof(ata_smart_log_entry) == 2);
 
 #pragma pack(1)
 struct ata_smart_log_directory {
@@ -474,7 +467,7 @@ struct ata_smart_log_directory {
   struct ata_smart_log_entry entry[255];
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_smart_log_directory, 512);
+STATIC_ASSERT(sizeof(ata_smart_log_directory) == 512);
 
 // SMART SELECTIVE SELF-TEST LOG Table 61 of T13/1532D Volume 1
 // Revision 3
@@ -484,7 +477,7 @@ struct test_span {
   uint64_t end;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(test_span, 16);
+STATIC_ASSERT(sizeof(test_span) == 16);
 
 #pragma pack(1)
 struct ata_selective_self_test_log {
@@ -501,7 +494,7 @@ struct ata_selective_self_test_log {
   unsigned char      checksum;
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_selective_self_test_log, 512);
+STATIC_ASSERT(sizeof(ata_selective_self_test_log) == 512);
 
 #define SELECTIVE_FLAG_DOSCAN  (0x0002)
 #define SELECTIVE_FLAG_PENDING (0x0008)
@@ -544,7 +537,7 @@ struct ata_sct_status_response
   unsigned char vendor_specific[32];// 480-511: vendor specific
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_sct_status_response, 512);
+STATIC_ASSERT(sizeof(ata_sct_status_response) == 512);
 
 // SCT Error Recovery Control command (send with SMART_WRITE_LOG page 0xe0)
 // Table 88 of T13/1699-D Revision 6a
@@ -558,7 +551,7 @@ struct ata_sct_error_recovery_control_command
   unsigned short words004_255[252]; // reserved
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_sct_error_recovery_control_command, 512);
+STATIC_ASSERT(sizeof(ata_sct_error_recovery_control_command) == 512);
 
 // SCT Feature Control command (send with SMART_WRITE_LOG page 0xe0)
 // Table 72 of T13/1699-D Revision 3f
@@ -573,7 +566,7 @@ struct ata_sct_feature_control_command
   unsigned short words005_255[251]; // reserved
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_sct_feature_control_command, 512);
+STATIC_ASSERT(sizeof(ata_sct_feature_control_command) == 512);
 
 // SCT Data Table command (send with SMART_WRITE_LOG page 0xe0)
 // Table 73 of T13/1699-D Revision 3f 
@@ -586,7 +579,7 @@ struct ata_sct_data_table_command
   unsigned short words003_255[253]; // reserved
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_sct_data_table_command, 512);
+STATIC_ASSERT(sizeof(ata_sct_data_table_command) == 512);
 
 // SCT Temperature History Table (read with SMART_READ_LOG page 0xe1)
 // Table 75 of T13/1699-D Revision 3f 
@@ -606,7 +599,7 @@ struct ata_sct_temperature_history_table
   signed char cb[478];              // 34-(34+cb_size-1): Circular buffer of temperature values
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(ata_sct_temperature_history_table, 512);
+STATIC_ASSERT(sizeof(ata_sct_temperature_history_table) == 512);
 
 // Possible values for span_args.mode
 enum {
diff --git a/smartmontools/dev_intelliprop.cpp b/smartmontools/dev_intelliprop.cpp
index 02738a7f0..c67cf615a 100644
--- a/smartmontools/dev_intelliprop.cpp
+++ b/smartmontools/dev_intelliprop.cpp
@@ -1,7 +1,7 @@
 /*
  * dev_intelliprop.cpp
  *
- * Home page of code is: http://www.smartmontools.org
+ * Home page of code is: https://www.smartmontools.org
  *
  * Copyright (C) 2016 Casey Biemiller  <cbiemiller@intelliprop.com>
  *
@@ -10,7 +10,7 @@
 
 #include "config.h"
 
-#include "atacmds.h" //ATTR_PACKED and ASSERT_SIZEOF_STRUCT
+#include "atacmds.h" // ATTR_PACKED, STATIC_ASSERT, ata_debugmode
 #include "dev_interface.h"
 #include "dev_intelliprop.h"
 #include "dev_tunnelled.h"
@@ -71,7 +71,7 @@ struct iprop_internal_log
   uint16_t crc;                // Bytes - [511:510] of Log C0
 } ATTR_PACKED;
 #pragma pack()
-ASSERT_SIZEOF_STRUCT(iprop_internal_log, 512);
+STATIC_ASSERT(sizeof(iprop_internal_log) == 512);
 
 /**
  * buffer is a pointer to a buffer of bytes, which should include data and
diff --git a/smartmontools/nvmecmds.cpp b/smartmontools/nvmecmds.cpp
index 577422579..f5be9ab41 100644
--- a/smartmontools/nvmecmds.cpp
+++ b/smartmontools/nvmecmds.cpp
@@ -1,9 +1,9 @@
 /*
  * nvmecmds.cpp
  *
- * Home page of code is: http://www.smartmontools.org
+ * Home page of code is: https://www.smartmontools.org
  *
- * Copyright (C) 2016 Christian Franke
+ * Copyright (C) 2016-19 Christian Franke
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
@@ -15,19 +15,12 @@ const char * nvmecmds_cvsid = "$Id$"
   NVMECMDS_H_CVSID;
 
 #include "dev_interface.h"
-#include "atacmds.h" // swapx(), ASSERT_*(), dont_print_serial_number
+#include "atacmds.h" // swapx(), dont_print_serial_number
 #include "scsicmds.h" // dStrHex()
 #include "utility.h"
 
 using namespace smartmontools;
 
-// Check nvme_* struct sizes
-ASSERT_SIZEOF_STRUCT(nvme_id_ctrl, 4096);
-ASSERT_SIZEOF_STRUCT(nvme_id_ns, 4096);
-ASSERT_SIZEOF_STRUCT(nvme_error_log_page, 64);
-ASSERT_SIZEOF_STRUCT(nvme_smart_log, 512);
-
-
 // Print NVMe debug messages?
 unsigned char nvme_debugmode = 0;
 
diff --git a/smartmontools/nvmecmds.h b/smartmontools/nvmecmds.h
index e9cd38fce..d478914ab 100644
--- a/smartmontools/nvmecmds.h
+++ b/smartmontools/nvmecmds.h
@@ -1,9 +1,9 @@
 /*
  * nvmecmds.h
  *
- * Home page of code is: http://www.smartmontools.org
+ * Home page of code is: https://www.smartmontools.org
  *
- * Copyright (C) 2016-18 Christian Franke
+ * Copyright (C) 2016-19 Christian Franke
  *
  * Original code from <linux/nvme.h>:
  *   Copyright (C) 2011-2014 Intel Corporation
@@ -16,6 +16,8 @@
 
 #define NVMECMDS_H_CVSID "$Id$"
 
+#include "static_assert.h"
+
 #include <stdint.h>
 
 // The code below was originally imported from <linux/nvme.h> include file from
@@ -38,6 +40,7 @@ struct nvme_error_log_page {
   unsigned char   vs;
   unsigned char   resv[35];
 };
+STATIC_ASSERT(sizeof(nvme_error_log_page) == 64);
 
 struct nvme_id_power_state {
   unsigned short  max_power; // centiwatts
@@ -56,6 +59,7 @@ struct nvme_id_power_state {
   unsigned char   active_work_scale;
   unsigned char   rsvd23[9];
 };
+STATIC_ASSERT(sizeof(nvme_id_power_state) == 32);
 
 struct nvme_id_ctrl {
   unsigned short  vid;
@@ -127,12 +131,14 @@ struct nvme_id_ctrl {
   struct nvme_id_power_state  psd[32];
   unsigned char   vs[1024];
 };
+STATIC_ASSERT(sizeof(nvme_id_ctrl) == 4096);
 
 struct nvme_lbaf {
   unsigned short  ms;
   unsigned char   ds;
   unsigned char   rp;
 };
+STATIC_ASSERT(sizeof(nvme_lbaf) == 4);
 
 struct nvme_id_ns {
   uint64_t        nsze;
@@ -163,6 +169,7 @@ struct nvme_id_ns {
   unsigned char   rsvd192[192];
   unsigned char   vs[3712];
 };
+STATIC_ASSERT(sizeof(nvme_id_ns) == 4096);
 
 struct nvme_smart_log {
   unsigned char  critical_warning;
@@ -190,6 +197,7 @@ struct nvme_smart_log {
   unsigned int   thm_temp2_total_time;
   unsigned char  rsvd232[280];
 };
+STATIC_ASSERT(sizeof(nvme_smart_log) == 512);
 
 enum nvme_admin_opcode {
 //nvme_admin_delete_sq     = 0x00,
diff --git a/smartmontools/os_win32.cpp b/smartmontools/os_win32.cpp
index 40b7226b6..e3c39dcb1 100644
--- a/smartmontools/os_win32.cpp
+++ b/smartmontools/os_win32.cpp
@@ -1,7 +1,7 @@
 /*
  * os_win32.cpp
  *
- * Home page of code is: http://www.smartmontools.org
+ * Home page of code is: https://www.smartmontools.org
  *
  * Copyright (C) 2004-19 Christian Franke
  *
@@ -81,19 +81,6 @@ extern unsigned char failuretest_permissive;
 // aacraid support
 #include "aacraid.h"
 
-// Silence -Wunused-local-typedefs warning from g++ >= 4.8
-#if __GNUC__ >= 4
-#define ATTR_UNUSED __attribute__((unused))
-#else
-#define ATTR_UNUSED /**/
-#endif
-
-// Macro to check constants at compile time using a dummy typedef
-#define ASSERT_CONST(c, n) \
-  typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED
-#define ASSERT_SIZEOF(t, n) \
-  typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED
-
 #ifndef _WIN64
 #define SELECT_WIN_32_64(x32, x64) (x32)
 #else
@@ -116,12 +103,12 @@ extern "C" {
 
 // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)
 
-ASSERT_CONST(SMART_GET_VERSION, 0x074080);
-ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);
-ASSERT_CONST(SMART_RCV_DRIVE_DATA, 0x07c088);
-ASSERT_SIZEOF(GETVERSIONINPARAMS, 24);
-ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);
-ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);
+STATIC_ASSERT(SMART_GET_VERSION == 0x074080);
+STATIC_ASSERT(SMART_SEND_DRIVE_COMMAND == 0x07c084);
+STATIC_ASSERT(SMART_RCV_DRIVE_DATA == 0x07c088);
+STATIC_ASSERT(sizeof(GETVERSIONINPARAMS) == 24);
+STATIC_ASSERT(sizeof(SENDCMDINPARAMS) == 32+1);
+STATIC_ASSERT(sizeof(SENDCMDOUTPARAMS) == 16+1);
 
 
 // IDE PASS THROUGH (2000, XP, undocumented)
@@ -143,8 +130,8 @@ typedef struct {
 
 #pragma pack()
 
-ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);
-ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);
+STATIC_ASSERT(IOCTL_IDE_PASS_THROUGH == 0x04d028);
+STATIC_ASSERT(sizeof(ATA_PASS_THROUGH) == 12+1);
 
 
 // ATA PASS THROUGH (Win2003, XP SP2)
@@ -178,16 +165,16 @@ typedef struct _ATA_PASS_THROUGH_EX {
 
 #endif // IOCTL_ATA_PASS_THROUGH
 
-ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);
-ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, SELECT_WIN_32_64(40, 48));
+STATIC_ASSERT(IOCTL_ATA_PASS_THROUGH == 0x04d02c);
+STATIC_ASSERT(sizeof(ATA_PASS_THROUGH_EX) == SELECT_WIN_32_64(40, 48));
 
 
 // IOCTL_SCSI_PASS_THROUGH[_DIRECT]
 
-ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);
-ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT, 0x04d014);
-ASSERT_SIZEOF(SCSI_PASS_THROUGH, SELECT_WIN_32_64(44, 56));
-ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT, SELECT_WIN_32_64(44, 56));
+STATIC_ASSERT(IOCTL_SCSI_PASS_THROUGH == 0x04d004);
+STATIC_ASSERT(IOCTL_SCSI_PASS_THROUGH_DIRECT == 0x04d014);
+STATIC_ASSERT(sizeof(SCSI_PASS_THROUGH) == SELECT_WIN_32_64(44, 56));
+STATIC_ASSERT(sizeof(SCSI_PASS_THROUGH_DIRECT) == SELECT_WIN_32_64(44, 56));
 
 
 // SMART IOCTL via SCSI MINIPORT ioctl
@@ -214,8 +201,8 @@ ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT, SELECT_WIN_32_64(44, 56));
 
 #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION
 
-ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);
-ASSERT_SIZEOF(SRB_IO_CONTROL, 28);
+STATIC_ASSERT(IOCTL_SCSI_MINIPORT == 0x04d008);
+STATIC_ASSERT(sizeof(SRB_IO_CONTROL) == 28);
 
 
 // IOCTL_STORAGE_QUERY_PROPERTY
@@ -266,9 +253,9 @@ typedef struct _STORAGE_PROPERTY_QUERY {
 
 #endif // IOCTL_STORAGE_QUERY_PROPERTY
 
-ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY, 0x002d1400);
-ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR, 36+1+3);
-ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY, 8+1+3);
+STATIC_ASSERT(IOCTL_STORAGE_QUERY_PROPERTY == 0x002d1400);
+STATIC_ASSERT(sizeof(STORAGE_DEVICE_DESCRIPTOR) == 36+1+3);
+STATIC_ASSERT(sizeof(STORAGE_PROPERTY_QUERY) == 8+1+3);
 
 
 // IOCTL_STORAGE_QUERY_PROPERTY: Windows 10 enhancements
@@ -305,15 +292,15 @@ namespace win10 {
     ULONG Reserved[3];
   } STORAGE_PROTOCOL_SPECIFIC_DATA;
 
-  ASSERT_SIZEOF(STORAGE_PROTOCOL_SPECIFIC_DATA, 40);
+  STATIC_ASSERT(sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) == 40);
 
 } // namespace win10
 
 
 // IOCTL_STORAGE_PREDICT_FAILURE
 
-ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE, 0x002d1100);
-ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512);
+STATIC_ASSERT(IOCTL_STORAGE_PREDICT_FAILURE == 0x002d1100);
+STATIC_ASSERT(sizeof(STORAGE_PREDICT_FAILURE) == 4+512);
 
 
 // 3ware specific versions of SMART ioctl structs
@@ -346,8 +333,8 @@ typedef struct _SENDCMDINPARAMS_EX {
 
 #pragma pack()
 
-ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONINPARAMS));
-ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));
+STATIC_ASSERT(sizeof(GETVERSIONINPARAMS_EX) == sizeof(GETVERSIONINPARAMS));
+STATIC_ASSERT(sizeof(SENDCMDINPARAMS_EX) == sizeof(SENDCMDINPARAMS));
 
 
 // NVME_PASS_THROUGH
@@ -378,21 +365,21 @@ typedef struct _NVME_PASS_THROUGH_IOCTL
 
 #endif // NVME_PASS_THROUGH_SRB_IO_CODE
 
-ASSERT_CONST(NVME_PASS_THROUGH_SRB_IO_CODE, (int)0xe0002000);
-ASSERT_SIZEOF(NVME_PASS_THROUGH_IOCTL, 152+1);
-ASSERT_SIZEOF(NVME_PASS_THROUGH_IOCTL, offsetof(NVME_PASS_THROUGH_IOCTL, DataBuffer)+1);
+STATIC_ASSERT(NVME_PASS_THROUGH_SRB_IO_CODE == (int)0xe0002000);
+STATIC_ASSERT(sizeof(NVME_PASS_THROUGH_IOCTL) == 152+1);
+STATIC_ASSERT(sizeof(NVME_PASS_THROUGH_IOCTL) == offsetof(NVME_PASS_THROUGH_IOCTL, DataBuffer)+1);
 
 
 // CSMI structs
 
-ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL));
-ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER, 204);
-ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER, 2080);
-ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER, 168);
+STATIC_ASSERT(sizeof(IOCTL_HEADER) == sizeof(SRB_IO_CONTROL));
+STATIC_ASSERT(sizeof(CSMI_SAS_DRIVER_INFO_BUFFER) == 204);
+STATIC_ASSERT(sizeof(CSMI_SAS_PHY_INFO_BUFFER) == 2080);
+STATIC_ASSERT(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) == 168);
 
 // aacraid struct
 
-ASSERT_SIZEOF(SCSI_REQUEST_BLOCK, SELECT_WIN_32_64(64, 88));
+STATIC_ASSERT(sizeof(SCSI_REQUEST_BLOCK) == SELECT_WIN_32_64(64, 88));
 
 } // extern "C"
 
@@ -912,7 +899,7 @@ static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, cha
     } params;
     char space[512-1];
   } sb;
-  ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
+  STATIC_ASSERT(sizeof(sb) == sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512);
   memset(&sb, 0, sizeof(sb));
 
   unsigned size;
@@ -1004,7 +991,7 @@ static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * d
     IDEREGS regs;
     UCHAR buffer[512];
   } sb;
-  ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
+  STATIC_ASSERT(sizeof(sb) == sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512);
 
   if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) {
     errno = EINVAL;
@@ -2027,9 +2014,7 @@ private:
 int csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info, port_2_index_map & p2i)
 {
   // max_number_of_ports must match CSMI_SAS_PHY_INFO.Phy[] array size
-  typedef char ASSERT_phy_info_size[
-    (int)(sizeof(phy_info.Phy) / sizeof(phy_info.Phy[0])) == max_number_of_ports ? 1 : -1]
-    ATTR_UNUSED;
+  STATIC_ASSERT(sizeof(phy_info.Phy) == max_number_of_ports * sizeof(phy_info.Phy[0]));
 
   // Get driver info to check CSMI support
   CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf;
@@ -2604,7 +2589,7 @@ bool win_tw_cli_device::open()
     pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":""));
 
   // Fake identify sector
-  ASSERT_SIZEOF(ata_identify_device, 512);
+  STATIC_ASSERT(sizeof(ata_identify_device) == 512);
   ata_identify_device * id = &m_ident_buf;
   memset(id, 0, sizeof(*id));
   copy_swapped(id->model    , findstr(buffer, " Model = "   ), sizeof(id->model));
diff --git a/smartmontools/os_win32/vc14/smartctl.vcxproj b/smartmontools/os_win32/vc14/smartctl.vcxproj
index d71d8c064..9faacb160 100644
--- a/smartmontools/os_win32/vc14/smartctl.vcxproj
+++ b/smartmontools/os_win32/vc14/smartctl.vcxproj
@@ -292,6 +292,7 @@
     <ClInclude Include="..\..\json.h" />
     <ClInclude Include="..\..\nvmecmds.h" />
     <ClInclude Include="..\..\nvmeprint.h" />
+    <ClInclude Include="..\..\static_assert.h" />
     <ClInclude Include="..\popen.h" />
     <ClInclude Include="config.h" />
     <ClInclude Include="svnversion.h" />
diff --git a/smartmontools/os_win32/vc14/smartctl.vcxproj.filters b/smartmontools/os_win32/vc14/smartctl.vcxproj.filters
index d44956c56..8577da519 100644
--- a/smartmontools/os_win32/vc14/smartctl.vcxproj.filters
+++ b/smartmontools/os_win32/vc14/smartctl.vcxproj.filters
@@ -110,6 +110,7 @@
     <ClInclude Include="..\..\nvmeprint.h" />
     <ClInclude Include="..\..\dev_intelliprop.h" />
     <ClInclude Include="..\..\json.h" />
+    <ClInclude Include="..\..\static_assert.h" />
     <ClInclude Include="..\..\getopt\getopt_int.h">
       <Filter>getopt</Filter>
     </ClInclude>
diff --git a/smartmontools/os_win32/vc14/smartd.vcxproj b/smartmontools/os_win32/vc14/smartd.vcxproj
index e53e93175..4f8a0c89b 100644
--- a/smartmontools/os_win32/vc14/smartd.vcxproj
+++ b/smartmontools/os_win32/vc14/smartd.vcxproj
@@ -310,6 +310,7 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClInclude>
+    <ClInclude Include="..\..\static_assert.h" />
     <ClInclude Include="..\daemon_win32.h" />
     <ClInclude Include="..\popen.h" />
     <ClInclude Include="..\syslog.h" />
diff --git a/smartmontools/os_win32/vc14/smartd.vcxproj.filters b/smartmontools/os_win32/vc14/smartd.vcxproj.filters
index 06cf09792..e833cdf58 100644
--- a/smartmontools/os_win32/vc14/smartd.vcxproj.filters
+++ b/smartmontools/os_win32/vc14/smartd.vcxproj.filters
@@ -111,6 +111,7 @@
     <ClInclude Include="..\..\nvmecmds.h" />
     <ClInclude Include="..\..\nvmeprint.h" />
     <ClInclude Include="..\..\dev_intelliprop.h" />
+    <ClInclude Include="..\..\static_assert.h" />
     <ClInclude Include="..\..\getopt\getopt_int.h">
       <Filter>getopt</Filter>
     </ClInclude>
diff --git a/smartmontools/static_assert.h b/smartmontools/static_assert.h
new file mode 100644
index 000000000..a240b2cb7
--- /dev/null
+++ b/smartmontools/static_assert.h
@@ -0,0 +1,27 @@
+/*
+ * static_assert.h
+ *
+ * Home page of code is: https://www.smartmontools.org
+ *
+ * Copyright (C) 2019 Christian Franke
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef STATIC_ASSERT_H
+#define STATIC_ASSERT_H
+
+#define STATIC_ASSERT_H_CVSID "$Id$"
+
+#if __cplusplus >= 201103 || _MSVC_LANG >= 201103
+#define STATIC_ASSERT(x) static_assert((x), #x)
+#elif __STDC_VERSION__ >= 201112
+#define STATIC_ASSERT(x) _Static_assert((x), #x)
+#elif __GNUC__ >= 4
+#define STATIC_ASSERT(x) typedef char static_assertion[(x) ? 1 : -1] \
+                         __attribute__((unused))
+#else
+#define STATIC_ASSERT(x) typedef char static_assertion[(x) ? 1 : -1]
+#endif
+
+#endif // STATIC_ASSERT_H
-- 
GitLab