@@ -82,7 +82,7 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
82
82
// Constants for TokenKinds.def
83
83
namespace {
84
84
85
- enum {
85
+ enum TokenKey : unsigned {
86
86
KEYC99 = 0x1 ,
87
87
KEYCXX = 0x2 ,
88
88
KEYCXX11 = 0x4 ,
@@ -99,70 +99,146 @@ namespace {
99
99
WCHARSUPPORT = 0x2000 ,
100
100
HALFSUPPORT = 0x4000 ,
101
101
CHAR8SUPPORT = 0x8000 ,
102
- KEYCONCEPTS = 0x10000 ,
103
- KEYOBJC = 0x20000 ,
104
- KEYZVECTOR = 0x40000 ,
105
- KEYCOROUTINES = 0x80000 ,
106
- KEYMODULES = 0x100000 ,
107
- KEYCXX20 = 0x200000 ,
108
- KEYOPENCLCXX = 0x400000 ,
109
- KEYMSCOMPAT = 0x800000 ,
110
- KEYSYCL = 0x1000000 ,
111
- KEYCUDA = 0x2000000 ,
102
+ KEYOBJC = 0x10000 ,
103
+ KEYZVECTOR = 0x20000 ,
104
+ KEYCOROUTINES = 0x40000 ,
105
+ KEYMODULES = 0x80000 ,
106
+ KEYCXX20 = 0x100000 ,
107
+ KEYOPENCLCXX = 0x200000 ,
108
+ KEYMSCOMPAT = 0x400000 ,
109
+ KEYSYCL = 0x800000 ,
110
+ KEYCUDA = 0x1000000 ,
112
111
KEYMAX = KEYCUDA, // The maximum key
113
112
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
114
113
KEYALL = (KEYMAX | (KEYMAX-1 )) & ~KEYNOMS18 &
115
114
~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
116
115
};
117
116
118
- // / How a keyword is treated in the selected standard.
117
+ // / How a keyword is treated in the selected standard. This enum is ordered
118
+ // / intentionally so that the value that 'wins' is the most 'permissive'.
119
119
enum KeywordStatus {
120
+ KS_Unknown, // Not yet calculated. Used when figuring out the status.
120
121
KS_Disabled, // Disabled
122
+ KS_Future, // Is a keyword in future standard
121
123
KS_Extension, // Is an extension
122
124
KS_Enabled, // Enabled
123
- KS_Future // Is a keyword in future standard
124
125
};
125
126
126
127
} // namespace
127
128
129
+ // This works on a single TokenKey flag and checks the LangOpts to get the
130
+ // KeywordStatus based exclusively on this flag, so that it can be merged in
131
+ // getKeywordStatus. Most should be enabled/disabled, but some might imply
132
+ // 'future' versions, or extensions. Returns 'unknown' unless this is KNOWN to
133
+ // be disabled, and the calling function makes it 'disabled' if no other flag
134
+ // changes it. This is necessary for the KEYNOCXX and KEYNOOPENCL flags.
135
+ static KeywordStatus getKeywordStatusHelper (const LangOptions &LangOpts,
136
+ TokenKey Flag) {
137
+ // Flag is a single bit version of TokenKey (that is, not
138
+ // KEYALL/KEYALLCXX/etc), so we can check with == throughout this function.
139
+ assert ((Flag & ~(Flag - 1 )) == Flag && " Multiple bits set?" );
140
+
141
+ switch (Flag) {
142
+ case KEYC99:
143
+ // FIXME: This should have KS_Future logic here, but that can only happen if
144
+ // getFutureCompatDiagKind ALSO gets updated. This is safe, since C mode is
145
+ // ALWAYS implied.
146
+ return LangOpts.C99 ? KS_Enabled : KS_Unknown;
147
+ case KEYC11:
148
+ // FIXME: This should have KS_Future logic here, but that can only happen if
149
+ // getFutureCompatDiagKind ALSO gets updated. This is safe, since C mode is
150
+ // ALWAYS implied.
151
+ return LangOpts.C11 ? KS_Enabled : KS_Unknown;
152
+ case KEYCXX:
153
+ return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;
154
+ case KEYCXX11:
155
+ if (LangOpts.CPlusPlus11 )
156
+ return KS_Enabled;
157
+ return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
158
+ case KEYCXX20:
159
+ if (LangOpts.CPlusPlus20 )
160
+ return KS_Enabled;
161
+ return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
162
+ case KEYGNU:
163
+ return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;
164
+ case KEYMS:
165
+ return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;
166
+ case BOOLSUPPORT:
167
+ return LangOpts.Bool ? KS_Enabled : KS_Unknown;
168
+ case KEYALTIVEC:
169
+ return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;
170
+ case KEYBORLAND:
171
+ return LangOpts.Borland ? KS_Extension : KS_Unknown;
172
+ case KEYOPENCLC:
173
+ return LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus ? KS_Enabled
174
+ : KS_Unknown;
175
+ case WCHARSUPPORT:
176
+ return LangOpts.WChar ? KS_Enabled : KS_Unknown;
177
+ case HALFSUPPORT:
178
+ return LangOpts.Half ? KS_Enabled : KS_Unknown;
179
+ case CHAR8SUPPORT:
180
+ if (LangOpts.Char8 ) return KS_Enabled;
181
+ if (LangOpts.CPlusPlus20 ) return KS_Unknown;
182
+ return KS_Future;
183
+ case KEYOBJC:
184
+ // We treat bridge casts as objective-C keywords so we can warn on them
185
+ // in non-arc mode.
186
+ return LangOpts.ObjC ? KS_Enabled : KS_Unknown;
187
+ case KEYZVECTOR:
188
+ return LangOpts.ZVector ? KS_Enabled : KS_Unknown;
189
+ case KEYCOROUTINES:
190
+ return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;
191
+ case KEYMODULES:
192
+ return LangOpts.ModulesTS ? KS_Enabled : KS_Unknown;
193
+ case KEYOPENCLCXX:
194
+ return LangOpts.OpenCLCPlusPlus ? KS_Enabled : KS_Unknown;
195
+ case KEYMSCOMPAT:
196
+ return LangOpts.MSVCCompat ? KS_Enabled : KS_Unknown;
197
+ case KEYSYCL:
198
+ return LangOpts.isSYCL () ? KS_Enabled : KS_Unknown;
199
+ case KEYCUDA:
200
+ return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
201
+ case KEYNOCXX:
202
+ // This is enabled in all non-C++ modes, but might be enabled for other
203
+ // reasons as well.
204
+ return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;
205
+ case KEYNOOPENCL:
206
+ // The disable behavior for this is handled in getKeywordStatus.
207
+ return KS_Unknown;
208
+ case KEYNOMS18:
209
+ // The disable behavior for this is handled in getKeywordStatus.
210
+ return KS_Unknown;
211
+ default :
212
+ llvm_unreachable (" Unknown KeywordStatus flag" );
213
+ }
214
+ }
215
+
128
216
// / Translates flags as specified in TokenKinds.def into keyword status
129
217
// / in the given language standard.
130
218
static KeywordStatus getKeywordStatus (const LangOptions &LangOpts,
131
219
unsigned Flags) {
220
+ // KEYALL means always enabled, so special case this one.
132
221
if (Flags == KEYALL) return KS_Enabled;
133
- if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled;
134
- if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled;
135
- if (LangOpts.CPlusPlus20 && (Flags & KEYCXX20)) return KS_Enabled;
136
- if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled;
137
- if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension;
138
- if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension;
139
- if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)) return KS_Enabled;
140
- if (LangOpts.Borland && (Flags & KEYBORLAND)) return KS_Extension;
141
- if (LangOpts.Bool && (Flags & BOOLSUPPORT)) return KS_Enabled;
142
- if (LangOpts.Half && (Flags & HALFSUPPORT)) return KS_Enabled;
143
- if (LangOpts.WChar && (Flags & WCHARSUPPORT)) return KS_Enabled;
144
- if (LangOpts.Char8 && (Flags & CHAR8SUPPORT)) return KS_Enabled;
145
- if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled;
146
- if (LangOpts.ZVector && (Flags & KEYZVECTOR)) return KS_Enabled;
147
- if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLC))
148
- return KS_Enabled;
149
- if (LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLCXX)) return KS_Enabled;
150
- if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) return KS_Enabled;
151
- if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled;
152
- // We treat bridge casts as objective-C keywords so we can warn on them
153
- // in non-arc mode.
154
- if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled;
155
- if (LangOpts.CPlusPlus20 && (Flags & KEYCONCEPTS)) return KS_Enabled;
156
- if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled;
157
- if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled;
158
- if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future;
159
- if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus20 && (Flags & CHAR8SUPPORT))
160
- return KS_Future;
161
- if (LangOpts.isSYCL () && (Flags & KEYSYCL))
162
- return KS_Enabled;
163
- if (LangOpts.CUDA && (Flags & KEYCUDA))
164
- return KS_Enabled;
165
- return KS_Disabled;
222
+ // These are tests that need to 'always win', as they are special in that they
223
+ // disable based on certain conditions.
224
+ if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) return KS_Disabled;
225
+ if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
226
+ !LangOpts.isCompatibleWithMSVC (LangOptions::MSVC2015))
227
+ return KS_Disabled;
228
+
229
+ KeywordStatus CurStatus = KS_Unknown;
230
+
231
+ while (Flags != 0 ) {
232
+ unsigned CurFlag = Flags & ~(Flags - 1 );
233
+ Flags = Flags & ~CurFlag;
234
+ CurStatus = std::max (
235
+ CurStatus,
236
+ getKeywordStatusHelper (LangOpts, static_cast <TokenKey>(CurFlag)));
237
+ }
238
+
239
+ if (CurStatus == KS_Unknown)
240
+ return KS_Disabled;
241
+ return CurStatus;
166
242
}
167
243
168
244
// / AddKeyword - This method is used to associate a token ID with specific
@@ -173,15 +249,6 @@ static void AddKeyword(StringRef Keyword,
173
249
const LangOptions &LangOpts, IdentifierTable &Table) {
174
250
KeywordStatus AddResult = getKeywordStatus (LangOpts, Flags);
175
251
176
- // Don't add this keyword under MSVCCompat.
177
- if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
178
- !LangOpts.isCompatibleWithMSVC (LangOptions::MSVC2015))
179
- return ;
180
-
181
- // Don't add this keyword under OpenCL.
182
- if (LangOpts.OpenCL && (Flags & KEYNOOPENCL))
183
- return ;
184
-
185
252
// Don't add this keyword if disabled in this language.
186
253
if (AddResult == KS_Disabled) return ;
187
254
0 commit comments