Eric Fiselier | fa1e5db | 2016-01-19 21:52:04 +0000 | [diff] [blame] | 1 | #===----------------------------------------------------------------------===## |
| 2 | # |
| 3 | # The LLVM Compiler Infrastructure |
| 4 | # |
| 5 | # This file is dual licensed under the MIT and the University of Illinois Open |
| 6 | # Source Licenses. See LICENSE.TXT for details. |
| 7 | # |
| 8 | #===----------------------------------------------------------------------===## |
| 9 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 10 | import platform |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 11 | import os |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 12 | import libcxx.util |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 13 | |
| 14 | |
| 15 | class CXXCompiler(object): |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 16 | CM_Default = 0 |
| 17 | CM_PreProcess = 1 |
| 18 | CM_Compile = 2 |
| 19 | CM_Link = 3 |
| 20 | |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 21 | def __init__(self, path, flags=None, compile_flags=None, link_flags=None, |
Eric Fiselier | d95f62e | 2016-12-06 01:02:15 +0000 | [diff] [blame] | 22 | warning_flags=None, verify_supported=None, |
| 23 | verify_flags=None, use_verify=False, |
| 24 | modules_flags=None, use_modules=False, |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 25 | use_ccache=False, use_warnings=False, compile_env=None, |
| 26 | cxx_type=None, cxx_version=None): |
Erik Pilkington | 64182a5 | 2017-05-19 23:02:49 +0000 | [diff] [blame] | 27 | self.source_lang = 'c++' |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 28 | self.path = path |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 29 | self.flags = list(flags or []) |
| 30 | self.compile_flags = list(compile_flags or []) |
| 31 | self.link_flags = list(link_flags or []) |
Eric Fiselier | d95f62e | 2016-12-06 01:02:15 +0000 | [diff] [blame] | 32 | self.warning_flags = list(warning_flags or []) |
| 33 | self.verify_supported = verify_supported |
| 34 | self.use_verify = use_verify |
| 35 | self.verify_flags = list(verify_flags or []) |
| 36 | assert not use_verify or verify_supported |
| 37 | assert not use_verify or verify_flags is not None |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 38 | self.modules_flags = list(modules_flags or []) |
| 39 | self.use_modules = use_modules |
| 40 | assert not use_modules or modules_flags is not None |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 41 | self.use_ccache = use_ccache |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 42 | self.use_warnings = use_warnings |
| 43 | if compile_env is not None: |
| 44 | self.compile_env = dict(compile_env) |
| 45 | else: |
| 46 | self.compile_env = None |
| 47 | self.type = cxx_type |
| 48 | self.version = cxx_version |
| 49 | if self.type is None or self.version is None: |
| 50 | self._initTypeAndVersion() |
| 51 | |
Eric Fiselier | d95f62e | 2016-12-06 01:02:15 +0000 | [diff] [blame] | 52 | def isVerifySupported(self): |
| 53 | if self.verify_supported is None: |
| 54 | self.verify_supported = self.hasCompileFlag(['-Xclang', |
| 55 | '-verify-ignore-unexpected']) |
| 56 | if self.verify_supported: |
| 57 | self.verify_flags = [ |
| 58 | '-Xclang', '-verify', |
| 59 | '-Xclang', '-verify-ignore-unexpected=note', |
| 60 | '-ferror-limit=1024' |
| 61 | ] |
| 62 | return self.verify_supported |
| 63 | |
| 64 | def useVerify(self, value=True): |
| 65 | self.use_verify = value |
| 66 | assert not self.use_verify or self.verify_flags is not None |
| 67 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 68 | def useModules(self, value=True): |
| 69 | self.use_modules = value |
| 70 | assert not self.use_modules or self.modules_flags is not None |
| 71 | |
| 72 | def useCCache(self, value=True): |
| 73 | self.use_ccache = value |
| 74 | |
| 75 | def useWarnings(self, value=True): |
| 76 | self.use_warnings = value |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 77 | |
| 78 | def _initTypeAndVersion(self): |
| 79 | # Get compiler type and version |
| 80 | macros = self.dumpMacros() |
| 81 | if macros is None: |
| 82 | return |
| 83 | compiler_type = None |
| 84 | major_ver = minor_ver = patchlevel = None |
| 85 | if '__clang__' in macros.keys(): |
| 86 | compiler_type = 'clang' |
| 87 | # Treat apple's llvm fork differently. |
| 88 | if '__apple_build_version__' in macros.keys(): |
| 89 | compiler_type = 'apple-clang' |
| 90 | major_ver = macros['__clang_major__'] |
| 91 | minor_ver = macros['__clang_minor__'] |
| 92 | patchlevel = macros['__clang_patchlevel__'] |
| 93 | elif '__GNUC__' in macros.keys(): |
| 94 | compiler_type = 'gcc' |
| 95 | major_ver = macros['__GNUC__'] |
| 96 | minor_ver = macros['__GNUC_MINOR__'] |
| 97 | patchlevel = macros['__GNUC_PATCHLEVEL__'] |
| 98 | self.type = compiler_type |
| 99 | self.version = (major_ver, minor_ver, patchlevel) |
| 100 | |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 101 | def _basicCmd(self, source_files, out, mode=CM_Default, flags=[], |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 102 | input_is_cxx=False): |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 103 | cmd = [] |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 104 | if self.use_ccache \ |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 105 | and not mode == self.CM_Link \ |
| 106 | and not mode == self.CM_PreProcess: |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 107 | cmd += ['ccache'] |
| 108 | cmd += [self.path] |
| 109 | if out is not None: |
| 110 | cmd += ['-o', out] |
Eric Fiselier | a769d7f | 2015-01-28 00:05:48 +0000 | [diff] [blame] | 111 | if input_is_cxx: |
Erik Pilkington | 64182a5 | 2017-05-19 23:02:49 +0000 | [diff] [blame] | 112 | cmd += ['-x', self.source_lang] |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 113 | if isinstance(source_files, list): |
| 114 | cmd += source_files |
| 115 | elif isinstance(source_files, str): |
| 116 | cmd += [source_files] |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 117 | else: |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 118 | raise TypeError('source_files must be a string or list') |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 119 | if mode == self.CM_PreProcess: |
| 120 | cmd += ['-E'] |
| 121 | elif mode == self.CM_Compile: |
| 122 | cmd += ['-c'] |
| 123 | cmd += self.flags |
Eric Fiselier | d95f62e | 2016-12-06 01:02:15 +0000 | [diff] [blame] | 124 | if self.use_verify: |
| 125 | cmd += self.verify_flags |
| 126 | assert mode in [self.CM_Default, self.CM_Compile] |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 127 | if self.use_modules: |
| 128 | cmd += self.modules_flags |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 129 | if mode != self.CM_Link: |
| 130 | cmd += self.compile_flags |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 131 | if self.use_warnings: |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 132 | cmd += self.warning_flags |
| 133 | if mode != self.CM_PreProcess and mode != self.CM_Compile: |
| 134 | cmd += self.link_flags |
| 135 | cmd += flags |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 136 | return cmd |
| 137 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 138 | def preprocessCmd(self, source_files, out=None, flags=[]): |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 139 | return self._basicCmd(source_files, out, flags=flags, |
| 140 | mode=self.CM_PreProcess, |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 141 | input_is_cxx=True) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 142 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 143 | def compileCmd(self, source_files, out=None, flags=[]): |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 144 | return self._basicCmd(source_files, out, flags=flags, |
| 145 | mode=self.CM_Compile, |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 146 | input_is_cxx=True) + ['-c'] |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 147 | |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 148 | def linkCmd(self, source_files, out=None, flags=[]): |
Eric Fiselier | 2edb326 | 2016-07-20 23:37:28 +0000 | [diff] [blame] | 149 | return self._basicCmd(source_files, out, flags=flags, |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 150 | mode=self.CM_Link) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 151 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 152 | def compileLinkCmd(self, source_files, out=None, flags=[]): |
| 153 | return self._basicCmd(source_files, out, flags=flags) |
| 154 | |
| 155 | def preprocess(self, source_files, out=None, flags=[], cwd=None): |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 156 | cmd = self.preprocessCmd(source_files, out, flags) |
Eric Fiselier | ed80386 | 2017-02-09 23:18:11 +0000 | [diff] [blame] | 157 | out, err, rc = libcxx.util.executeCommand(cmd, env=self.compile_env, |
| 158 | cwd=cwd) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 159 | return cmd, out, err, rc |
| 160 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 161 | def compile(self, source_files, out=None, flags=[], cwd=None): |
| 162 | cmd = self.compileCmd(source_files, out, flags) |
Eric Fiselier | ed80386 | 2017-02-09 23:18:11 +0000 | [diff] [blame] | 163 | out, err, rc = libcxx.util.executeCommand(cmd, env=self.compile_env, |
| 164 | cwd=cwd) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 165 | return cmd, out, err, rc |
| 166 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 167 | def link(self, source_files, out=None, flags=[], cwd=None): |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 168 | cmd = self.linkCmd(source_files, out, flags) |
Eric Fiselier | ed80386 | 2017-02-09 23:18:11 +0000 | [diff] [blame] | 169 | out, err, rc = libcxx.util.executeCommand(cmd, env=self.compile_env, |
| 170 | cwd=cwd) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 171 | return cmd, out, err, rc |
| 172 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 173 | def compileLink(self, source_files, out=None, flags=[], |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 174 | cwd=None): |
| 175 | cmd = self.compileLinkCmd(source_files, out, flags) |
Eric Fiselier | ed80386 | 2017-02-09 23:18:11 +0000 | [diff] [blame] | 176 | out, err, rc = libcxx.util.executeCommand(cmd, env=self.compile_env, |
| 177 | cwd=cwd) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 178 | return cmd, out, err, rc |
| 179 | |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 180 | def compileLinkTwoSteps(self, source_file, out=None, object_file=None, |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 181 | flags=[], cwd=None): |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 182 | if not isinstance(source_file, str): |
| 183 | raise TypeError('This function only accepts a single input file') |
| 184 | if object_file is None: |
| 185 | # Create, use and delete a temporary object file if none is given. |
| 186 | with_fn = lambda: libcxx.util.guardedTempFilename(suffix='.o') |
| 187 | else: |
| 188 | # Otherwise wrap the filename in a context manager function. |
| 189 | with_fn = lambda: libcxx.util.nullContext(object_file) |
| 190 | with with_fn() as object_file: |
Logan Chien | 21f5b24 | 2015-05-17 00:24:11 +0000 | [diff] [blame] | 191 | cc_cmd, cc_stdout, cc_stderr, rc = self.compile( |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 192 | source_file, object_file, flags=flags, cwd=cwd) |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 193 | if rc != 0: |
Logan Chien | 21f5b24 | 2015-05-17 00:24:11 +0000 | [diff] [blame] | 194 | return cc_cmd, cc_stdout, cc_stderr, rc |
| 195 | |
| 196 | link_cmd, link_stdout, link_stderr, rc = self.link( |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 197 | object_file, out=out, flags=flags, cwd=cwd) |
Logan Chien | 21f5b24 | 2015-05-17 00:24:11 +0000 | [diff] [blame] | 198 | return (cc_cmd + ['&&'] + link_cmd, cc_stdout + link_stdout, |
| 199 | cc_stderr + link_stderr, rc) |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 200 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 201 | def dumpMacros(self, source_files=None, flags=[], cwd=None): |
Eric Fiselier | dd7a483 | 2015-01-22 18:05:58 +0000 | [diff] [blame] | 202 | if source_files is None: |
| 203 | source_files = os.devnull |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 204 | flags = ['-dM'] + flags |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 205 | cmd, out, err, rc = self.preprocess(source_files, flags=flags, cwd=cwd) |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 206 | if rc != 0: |
Eric Fiselier | 5fe8797 | 2017-10-02 22:52:51 +0000 | [diff] [blame] | 207 | return cmd, out, err, rc |
Eric Fiselier | 9ef5d45 | 2015-01-20 16:14:18 +0000 | [diff] [blame] | 208 | parsed_macros = {} |
Eric Fiselier | 28a058b | 2015-01-16 21:35:08 +0000 | [diff] [blame] | 209 | lines = [l.strip() for l in out.split('\n') if l.strip()] |
| 210 | for l in lines: |
| 211 | assert l.startswith('#define ') |
| 212 | l = l[len('#define '):] |
| 213 | macro, _, value = l.partition(' ') |
| 214 | parsed_macros[macro] = value |
| 215 | return parsed_macros |
| 216 | |
| 217 | def getTriple(self): |
| 218 | cmd = [self.path] + self.flags + ['-dumpmachine'] |
Eric Fiselier | ed80386 | 2017-02-09 23:18:11 +0000 | [diff] [blame] | 219 | return libcxx.util.capture(cmd).strip() |
Eric Fiselier | a985b8c | 2015-05-19 15:15:53 +0000 | [diff] [blame] | 220 | |
| 221 | def hasCompileFlag(self, flag): |
Eric Fiselier | faaf5ee | 2015-07-06 19:56:45 +0000 | [diff] [blame] | 222 | if isinstance(flag, list): |
| 223 | flags = list(flag) |
| 224 | else: |
| 225 | flags = [flag] |
Eric Fiselier | a985b8c | 2015-05-19 15:15:53 +0000 | [diff] [blame] | 226 | # Add -Werror to ensure that an unrecognized flag causes a non-zero |
| 227 | # exit code. -Werror is supported on all known compiler types. |
| 228 | if self.type is not None: |
Eric Fiselier | 78c020b | 2016-10-14 10:30:33 +0000 | [diff] [blame] | 229 | flags += ['-Werror', '-fsyntax-only'] |
Eric Fiselier | a985b8c | 2015-05-19 15:15:53 +0000 | [diff] [blame] | 230 | cmd, out, err, rc = self.compile(os.devnull, out=os.devnull, |
| 231 | flags=flags) |
| 232 | return rc == 0 |
Eric Fiselier | 7b86ce5 | 2015-07-18 21:17:16 +0000 | [diff] [blame] | 233 | |
Eric Fiselier | 6e467a8 | 2016-11-13 22:27:00 +0000 | [diff] [blame] | 234 | def addFlagIfSupported(self, flag): |
| 235 | if isinstance(flag, list): |
| 236 | flags = list(flag) |
| 237 | else: |
| 238 | flags = [flag] |
| 239 | if self.hasCompileFlag(flags): |
| 240 | self.flags += flags |
| 241 | return True |
| 242 | else: |
| 243 | return False |
| 244 | |
Eric Fiselier | 7b86ce5 | 2015-07-18 21:17:16 +0000 | [diff] [blame] | 245 | def addCompileFlagIfSupported(self, flag): |
| 246 | if isinstance(flag, list): |
| 247 | flags = list(flag) |
| 248 | else: |
| 249 | flags = [flag] |
| 250 | if self.hasCompileFlag(flags): |
| 251 | self.compile_flags += flags |
| 252 | return True |
| 253 | else: |
| 254 | return False |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 255 | |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 256 | def hasWarningFlag(self, flag): |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 257 | """ |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 258 | hasWarningFlag - Test if the compiler supports a given warning flag. |
| 259 | Unlike addCompileFlagIfSupported, this function detects when |
| 260 | "-Wno-<warning>" flags are unsupported. If flag is a |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 261 | "-Wno-<warning>" GCC will not emit an unknown option diagnostic unless |
| 262 | another error is triggered during compilation. |
| 263 | """ |
| 264 | assert isinstance(flag, str) |
Eric Fiselier | ab9ab94 | 2016-12-24 04:34:33 +0000 | [diff] [blame] | 265 | assert flag.startswith('-W') |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 266 | if not flag.startswith('-Wno-'): |
Eric Fiselier | ab9ab94 | 2016-12-24 04:34:33 +0000 | [diff] [blame] | 267 | return self.hasCompileFlag(flag) |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 268 | flags = ['-Werror', flag] |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 269 | old_use_warnings = self.use_warnings |
| 270 | self.useWarnings(False) |
| 271 | cmd = self.compileCmd('-', os.devnull, flags) |
Eric Fiselier | ab9ab94 | 2016-12-24 04:34:33 +0000 | [diff] [blame] | 272 | self.useWarnings(old_use_warnings) |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 273 | # Remove '-v' because it will cause the command line invocation |
| 274 | # to be printed as part of the error output. |
| 275 | # TODO(EricWF): Are there other flags we need to worry about? |
| 276 | if '-v' in cmd: |
| 277 | cmd.remove('-v') |
Eric Fiselier | ed80386 | 2017-02-09 23:18:11 +0000 | [diff] [blame] | 278 | out, err, rc = libcxx.util.executeCommand( |
| 279 | cmd, input=libcxx.util.to_bytes('#error\n')) |
Eric Fiselier | ab9ab94 | 2016-12-24 04:34:33 +0000 | [diff] [blame] | 280 | |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 281 | assert rc != 0 |
| 282 | if flag in err: |
| 283 | return False |
Eric Fiselier | e94b484 | 2015-08-26 20:17:33 +0000 | [diff] [blame] | 284 | return True |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 285 | |
| 286 | def addWarningFlagIfSupported(self, flag): |
| 287 | if self.hasWarningFlag(flag): |
Eric Fiselier | ebaf7da | 2017-01-13 22:02:08 +0000 | [diff] [blame] | 288 | if flag not in self.warning_flags: |
| 289 | self.warning_flags += [flag] |
Eric Fiselier | bca6de0 | 2016-12-05 23:16:07 +0000 | [diff] [blame] | 290 | return True |
| 291 | return False |