From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by sourceware.org (Postfix) with ESMTPS id A1FC73846078 for ; Thu, 13 Aug 2020 12:58:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A1FC73846078 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=andrew.burgess@embecosm.com Received: by mail-wm1-x342.google.com with SMTP id c80so4613963wme.0 for ; Thu, 13 Aug 2020 05:58:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2CrhJc+jEvBncpaT6/zVxAo+Rra1/I6zdi/JWZidlec=; b=J/rTYg9Cqr+OpT6CRTg+MXmVmIH2M4vrr8orocBKXA89mxjG45z9rd/elrtHTKuV4I l+Pm5mxznRoYRQBoxQCLoyjdldhPwfJlIoNFLVYES5p2tlYV7F341xjg1utUCnmtnKex Qm/YvoD0oAVjDWf9OXuueqg1PN0sTwcRH9obr1bttSr9YmoU+mns2mKO5jYBsSTFXXDl PTDe18qXduKyOkQgx4j93Byjzrq3YeugX3y46xPHMlLTAhRPIRXjgc0dPC01vTx+xN0J FaOU6Ct+pm21X4XK/CBmyVW6ttQgOJboJ78UxKKVez6eXGmGjJzJ29cIKy2Go5/Lzl9C TfjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2CrhJc+jEvBncpaT6/zVxAo+Rra1/I6zdi/JWZidlec=; b=DAZeGr/YrfjTfYv7k11VhyLXYjropsNzU44MtVxMTZoI2b7ZIxjGHxph8q3VCHNyVw BF1o3SoGvnN/co+Bh6YINmaiYyOIV6vnQ5effMzLld6iFJcIuavfuiL7JTMKZYNcgUh0 iTcRIlERaWq8FbZHGMKH+Yj0vtXX2PVxXtyMoTV0bHItjGq5lx0IjWPySjxaWXvwNWjR ++fr5VOWcSclCtQfgcxKr7l3ink/T7CnsDYg7pq9CvL2KhWy5SKo7ZPH0BHd81Sqr/OI CwNvzw9IKkoNirsBLdo4Li/+JUPO4e67p6plSkzQqMuZfCfZV8j3Ru7F3rBiyJ1qfBAh xnIg== X-Gm-Message-State: AOAM531mcEIFhABlqyf1NCVkbnW3FrKBz+rcomh5y8hG8F/SmUNUagAb NigahZKZlsQtj9e+2HxJ062S1pvqonE= X-Google-Smtp-Source: ABdhPJy4+rACeVkaDiY8RYFKyYJBlpXu85A7rLBWYonHWZo7UXcIdc99RJkGCXhcUQzyAziOSGPFDg== X-Received: by 2002:a1c:a553:: with SMTP id o80mr4247098wme.50.1597323532346; Thu, 13 Aug 2020 05:58:52 -0700 (PDT) Received: from localhost (host86-186-80-213.range86-186.btcentralplus.com. [86.186.80.213]) by smtp.gmail.com with ESMTPSA id z10sm9516668wmg.13.2020.08.13.05.58.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2020 05:58:51 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: [PATCH 1/8] gdbsupport: Provide global operators |=, &=, and ^= for enum bit flags Date: Thu, 13 Aug 2020 13:58:38 +0100 Message-Id: <8eb7f409ca572c526de08ab23878be905f5fef42.1597319264.git.andrew.burgess@embecosm.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 13 Aug 2020 12:58:55 -0000 The current enum bit flags mechanism provides global operators &, |, ^, ~, but does not provide &=, |=, ^=. The implementation for one of these, |=, would look like this: template typename enum_flags_type::type & operator|= (enum_type &e1, enum_type e2) { e1 = enum_flags (e1) | e2; return e1; } Then if we create a test within GDB like this: enum some_flag { flag_val1 = 1 << 1, flag_val2 = 1 << 2, flag_val3 = 1 << 3, flag_val4 = 1 << 4, }; DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags); ... enum some_flag f = flag_val1 | flag_val2; f |= flag_val3; Initially this didn't compile, with an error like: ..../gdbsupport/enum-flags.h: In instantiation of ‘typename enum_flags_type::type& operator|=(enum_type&, enum_type) [with enum_type = some_flag; typename enum_flags_type::type = enum_flags]’: ..../gdb/main.c:168:8: required from here ..../gdbsupport/enum-flags.h:217:10: error: cannot bind non-const lvalue reference of type ‘enum_flags_type::type&’ {aka ‘enum_flags&’} to an rvalue of type ‘enum_flags_type::type’ {aka ‘enum_flags’} 217 | return e1; | ^~ ..../gdbsupport/enum-flags.h:125:3: note: after user-defined conversion: ‘enum_flags::enum_flags(enum_flags::enum_type) [with E = some_flag; enum_flags::enum_type = some_flag]’ 125 | enum_flags (enum_type e) | ^~~~~~~~~~ If we look at enum_flags_type, which is used in the return type of our operator, it looks like this: template<> struct enum_flags_type { typedef enum_flags type; } So, with `typename' and `typedef' resolved, our new operator actually compiled like this: template enum_flags & operator|= (enum_type &e1, enum_type e2) { e1 = enum_flags (e1) | e2; return e1; } And I think this makes the problem clearer (maybe), the return type reference is different to the argument types, so the compiler is forced to try and create a temporary (the result of converting `e1' to type `enum_flags') and return a reference to that temporary. What I'd like is for the return type to match the arguments, and this can be achieved I think by changing the enum_flags_type definition to this: template<> struct enum_flags_type { typedef enum_type type; } Now, once the `typename' and `typedef' are resolved, our new operator compiles as this: template enum_type & operator|= (enum_type &e1, enum_type e2) { e1 = enum_flags (e1) | e2; return e1; } And indeed our original example now compiles fine. The final thing we must take care to check is that the global operators are not now picking up _all_ enums, after all, this is part of what the enum-flags.h file does for us, bitwise operators where we ask for it, and not otherwise. A manual test on my demo above (with some_flags) confirms that removing the DEF_ENUM_FLAGS_TYPE line still prevents the code from compiling as we'd hope, this is because, just like before `enum_flags_type::type' is only defined for the enums that have DEF_ENUM_FLAGS_TYPE applied to them. gdbsupport/ChangeLog: * enum-flags.h (DEF_ENUM_FLAGS_TYPE): Update header comment, and define enum_flags_type::type differently. (operator|=): New. (operator&=): New. (operator^=): New. --- gdbsupport/ChangeLog | 8 ++++++++ gdbsupport/enum-flags.h | 30 +++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/gdbsupport/enum-flags.h b/gdbsupport/enum-flags.h index 825ff4faf2c..78db3c7d88e 100644 --- a/gdbsupport/enum-flags.h +++ b/gdbsupport/enum-flags.h @@ -55,15 +55,15 @@ instantiating for non-flag enums. */ template struct enum_flags_type {}; -/* Use this to mark an enum as flags enum. It defines FLAGS as +/* Use this to mark an enum as flags enum. It defines FLAGS_TYPE as enum_flags wrapper class for ENUM, and enables the global operator - overloads for ENUM. */ + overloads for ENUM_TYPE. */ #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \ typedef enum_flags flags_type; \ template<> \ struct enum_flags_type \ { \ - typedef enum_flags type; \ + typedef enum_type type; \ } /* Until we can rely on std::underlying type being universally @@ -209,6 +209,30 @@ operator~ (enum_type e) return ~enum_flags (e); } +template +typename enum_flags_type::type +operator|= (enum_type &e1, const enum_type &e2) +{ + e1 = enum_flags (e1) | e2; + return e1; +} + +template +typename enum_flags_type::type +operator&= (enum_type &e1, const enum_type &e2) +{ + e1 = enum_flags (e1) & e2; + return e1; +} + +template +typename enum_flags_type::type +operator^= (enum_type &e1, const enum_type &e2) +{ + e1 = enum_flags (e1) ^ e2; + return e1; +} + #else /* __cplusplus */ /* In C, the flags type is just a typedef for the enum type. */ -- 2.25.4