1 | //===----- SemaTypeTraits.cpp - Semantic Analysis for C++ Type Traits -----===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements semantic analysis for C++ type traits. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/AST/DeclCXX.h" |
14 | #include "clang/AST/Type.h" |
15 | #include "clang/Basic/DiagnosticParse.h" |
16 | #include "clang/Basic/DiagnosticSema.h" |
17 | #include "clang/Basic/TypeTraits.h" |
18 | #include "clang/Sema/EnterExpressionEvaluationContext.h" |
19 | #include "clang/Sema/Initialization.h" |
20 | #include "clang/Sema/Lookup.h" |
21 | #include "clang/Sema/Overload.h" |
22 | #include "clang/Sema/Sema.h" |
23 | #include "clang/Sema/SemaHLSL.h" |
24 | |
25 | using namespace clang; |
26 | |
27 | static CXXMethodDecl *LookupSpecialMemberFromXValue(Sema &SemaRef, |
28 | const CXXRecordDecl *RD, |
29 | bool Assign) { |
30 | RD = RD->getDefinition(); |
31 | SourceLocation LookupLoc = RD->getLocation(); |
32 | |
33 | CanQualType CanTy = SemaRef.getASTContext().getCanonicalType( |
34 | T: SemaRef.getASTContext().getTagDeclType(Decl: RD)); |
35 | DeclarationName Name; |
36 | Expr *Arg = nullptr; |
37 | unsigned NumArgs; |
38 | |
39 | QualType ArgType = CanTy; |
40 | ExprValueKind VK = clang::VK_XValue; |
41 | |
42 | if (Assign) |
43 | Name = |
44 | SemaRef.getASTContext().DeclarationNames.getCXXOperatorName(Op: OO_Equal); |
45 | else |
46 | Name = |
47 | SemaRef.getASTContext().DeclarationNames.getCXXConstructorName(Ty: CanTy); |
48 | |
49 | OpaqueValueExpr FakeArg(LookupLoc, ArgType, VK); |
50 | NumArgs = 1; |
51 | Arg = &FakeArg; |
52 | |
53 | // Create the object argument |
54 | QualType ThisTy = CanTy; |
55 | Expr::Classification Classification = |
56 | OpaqueValueExpr(LookupLoc, ThisTy, VK_LValue) |
57 | .Classify(Ctx&: SemaRef.getASTContext()); |
58 | |
59 | // Now we perform lookup on the name we computed earlier and do overload |
60 | // resolution. Lookup is only performed directly into the class since there |
61 | // will always be a (possibly implicit) declaration to shadow any others. |
62 | OverloadCandidateSet OCS(LookupLoc, OverloadCandidateSet::CSK_Normal); |
63 | DeclContext::lookup_result R = RD->lookup(Name); |
64 | |
65 | if (R.empty()) |
66 | return nullptr; |
67 | |
68 | // Copy the candidates as our processing of them may load new declarations |
69 | // from an external source and invalidate lookup_result. |
70 | SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end()); |
71 | |
72 | for (NamedDecl *CandDecl : Candidates) { |
73 | if (CandDecl->isInvalidDecl()) |
74 | continue; |
75 | |
76 | DeclAccessPair Cand = DeclAccessPair::make(D: CandDecl, AS: clang::AS_none); |
77 | auto CtorInfo = getConstructorInfo(ND: Cand); |
78 | if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Val: Cand->getUnderlyingDecl())) { |
79 | if (Assign) |
80 | SemaRef.AddMethodCandidate(Method: M, FoundDecl: Cand, ActingContext: const_cast<CXXRecordDecl *>(RD), |
81 | ObjectType: ThisTy, ObjectClassification: Classification, |
82 | Args: llvm::ArrayRef(&Arg, NumArgs), CandidateSet&: OCS, SuppressUserConversions: true); |
83 | else { |
84 | assert(CtorInfo); |
85 | SemaRef.AddOverloadCandidate(Function: CtorInfo.Constructor, FoundDecl: CtorInfo.FoundDecl, |
86 | Args: llvm::ArrayRef(&Arg, NumArgs), CandidateSet&: OCS, |
87 | /*SuppressUserConversions*/ true); |
88 | } |
89 | } else if (FunctionTemplateDecl *Tmpl = |
90 | dyn_cast<FunctionTemplateDecl>(Val: Cand->getUnderlyingDecl())) { |
91 | if (Assign) |
92 | SemaRef.AddMethodTemplateCandidate( |
93 | MethodTmpl: Tmpl, FoundDecl: Cand, ActingContext: const_cast<CXXRecordDecl *>(RD), ExplicitTemplateArgs: nullptr, ObjectType: ThisTy, |
94 | ObjectClassification: Classification, Args: llvm::ArrayRef(&Arg, NumArgs), CandidateSet&: OCS, SuppressUserConversions: true); |
95 | else { |
96 | assert(CtorInfo); |
97 | SemaRef.AddTemplateOverloadCandidate( |
98 | FunctionTemplate: CtorInfo.ConstructorTmpl, FoundDecl: CtorInfo.FoundDecl, ExplicitTemplateArgs: nullptr, |
99 | Args: llvm::ArrayRef(&Arg, NumArgs), CandidateSet&: OCS, SuppressUserConversions: true); |
100 | } |
101 | } |
102 | } |
103 | |
104 | OverloadCandidateSet::iterator Best; |
105 | switch (OCS.BestViableFunction(S&: SemaRef, Loc: LookupLoc, Best)) { |
106 | case OR_Success: |
107 | case OR_Deleted: |
108 | return cast<CXXMethodDecl>(Val: Best->Function)->getCanonicalDecl(); |
109 | default: |
110 | return nullptr; |
111 | } |
112 | } |
113 | |
114 | static bool hasSuitableConstructorForRelocation(Sema &SemaRef, |
115 | const CXXRecordDecl *D, |
116 | bool AllowUserDefined) { |
117 | assert(D->hasDefinition() && !D->isInvalidDecl()); |
118 | |
119 | if (D->hasSimpleMoveConstructor() || D->hasSimpleCopyConstructor()) |
120 | return true; |
121 | |
122 | CXXMethodDecl *Decl = |
123 | LookupSpecialMemberFromXValue(SemaRef, RD: D, /*Assign=*/false); |
124 | return Decl && (AllowUserDefined || !Decl->isUserProvided()) && |
125 | !Decl->isDeleted(); |
126 | } |
127 | |
128 | static bool hasSuitableMoveAssignmentOperatorForRelocation( |
129 | Sema &SemaRef, const CXXRecordDecl *D, bool AllowUserDefined) { |
130 | assert(D->hasDefinition() && !D->isInvalidDecl()); |
131 | |
132 | if (D->hasSimpleMoveAssignment() || D->hasSimpleCopyAssignment()) |
133 | return true; |
134 | |
135 | CXXMethodDecl *Decl = |
136 | LookupSpecialMemberFromXValue(SemaRef, RD: D, /*Assign=*/true); |
137 | if (!Decl) |
138 | return false; |
139 | |
140 | return Decl && (AllowUserDefined || !Decl->isUserProvided()) && |
141 | !Decl->isDeleted(); |
142 | } |
143 | |
144 | // [C++26][class.prop] |
145 | // A class C is default-movable if |
146 | // - overload resolution for direct-initializing an object of type C |
147 | // from an xvalue of type C selects a constructor that is a direct member of C |
148 | // and is neither user-provided nor deleted, |
149 | // - overload resolution for assigning to an lvalue of type C from an xvalue of |
150 | // type C selects an assignment operator function that is a direct member of C |
151 | // and is neither user-provided nor deleted, and C has a destructor that is |
152 | // neither user-provided nor deleted. |
153 | static bool IsDefaultMovable(Sema &SemaRef, const CXXRecordDecl *D) { |
154 | if (!hasSuitableConstructorForRelocation(SemaRef, D, |
155 | /*AllowUserDefined=*/false)) |
156 | return false; |
157 | |
158 | if (!hasSuitableMoveAssignmentOperatorForRelocation( |
159 | SemaRef, D, /*AllowUserDefined=*/false)) |
160 | return false; |
161 | |
162 | CXXDestructorDecl *Dtr = D->getDestructor(); |
163 | |
164 | if (!Dtr) |
165 | return true; |
166 | |
167 | Dtr = Dtr->getCanonicalDecl(); |
168 | |
169 | if (Dtr->isUserProvided() && (!Dtr->isDefaulted() || Dtr->isDeleted())) |
170 | return false; |
171 | |
172 | return !Dtr->isDeleted(); |
173 | } |
174 | |
175 | // [C++26][class.prop] |
176 | // A class is eligible for trivial relocation unless it... |
177 | static bool IsEligibleForTrivialRelocation(Sema &SemaRef, |
178 | const CXXRecordDecl *D) { |
179 | |
180 | for (const CXXBaseSpecifier &B : D->bases()) { |
181 | const auto *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
182 | if (!BaseDecl) |
183 | continue; |
184 | // ... has any virtual base classes |
185 | // ... has a base class that is not a trivially relocatable class |
186 | if (B.isVirtual() || (!BaseDecl->isDependentType() && |
187 | !SemaRef.IsCXXTriviallyRelocatableType(T: B.getType()))) |
188 | return false; |
189 | } |
190 | |
191 | bool IsUnion = D->isUnion(); |
192 | for (const FieldDecl *Field : D->fields()) { |
193 | if (Field->getType()->isDependentType()) |
194 | continue; |
195 | if (Field->getType()->isReferenceType()) |
196 | continue; |
197 | // ... has a non-static data member of an object type that is not |
198 | // of a trivially relocatable type |
199 | if (!SemaRef.IsCXXTriviallyRelocatableType(T: Field->getType())) |
200 | return false; |
201 | |
202 | // A union contains values with address discriminated pointer auth |
203 | // cannot be relocated. |
204 | if (IsUnion && SemaRef.Context.containsAddressDiscriminatedPointerAuth( |
205 | T: Field->getType())) |
206 | return false; |
207 | } |
208 | return !D->hasDeletedDestructor(); |
209 | } |
210 | |
211 | // [C++26][class.prop] |
212 | // A class C is eligible for replacement unless |
213 | static bool IsEligibleForReplacement(Sema &SemaRef, const CXXRecordDecl *D) { |
214 | |
215 | for (const CXXBaseSpecifier &B : D->bases()) { |
216 | const auto *BaseDecl = B.getType()->getAsCXXRecordDecl(); |
217 | if (!BaseDecl) |
218 | continue; |
219 | // it has a base class that is not a replaceable class |
220 | if (!BaseDecl->isDependentType() && |
221 | !SemaRef.IsCXXReplaceableType(T: B.getType())) |
222 | return false; |
223 | } |
224 | |
225 | for (const FieldDecl *Field : D->fields()) { |
226 | if (Field->getType()->isDependentType()) |
227 | continue; |
228 | |
229 | // it has a non-static data member that is not of a replaceable type, |
230 | if (!SemaRef.IsCXXReplaceableType(T: Field->getType())) |
231 | return false; |
232 | } |
233 | return !D->hasDeletedDestructor(); |
234 | } |
235 | |
236 | ASTContext::CXXRecordDeclRelocationInfo |
237 | Sema::CheckCXX2CRelocatableAndReplaceable(const CXXRecordDecl *D) { |
238 | ASTContext::CXXRecordDeclRelocationInfo Info{.IsRelocatable: false, .IsReplaceable: false}; |
239 | |
240 | if (!getLangOpts().CPlusPlus || D->isInvalidDecl()) |
241 | return Info; |
242 | |
243 | assert(D->hasDefinition()); |
244 | |
245 | // This is part of "eligible for replacement", however we defer it |
246 | // to avoid extraneous computations. |
247 | auto HasSuitableSMP = [&] { |
248 | return hasSuitableConstructorForRelocation(SemaRef&: *this, D, |
249 | /*AllowUserDefined=*/true) && |
250 | hasSuitableMoveAssignmentOperatorForRelocation( |
251 | SemaRef&: *this, D, /*AllowUserDefined=*/true); |
252 | }; |
253 | |
254 | auto IsUnion = [&, Is = std::optional<bool>{}]() mutable { |
255 | if (!Is.has_value()) |
256 | Is = D->isUnion() && !D->hasUserDeclaredCopyConstructor() && |
257 | !D->hasUserDeclaredCopyAssignment() && |
258 | !D->hasUserDeclaredMoveOperation() && |
259 | !D->hasUserDeclaredDestructor(); |
260 | return *Is; |
261 | }; |
262 | |
263 | auto IsDefaultMovable = [&, Is = std::optional<bool>{}]() mutable { |
264 | if (!Is.has_value()) |
265 | Is = ::IsDefaultMovable(SemaRef&: *this, D); |
266 | return *Is; |
267 | }; |
268 | |
269 | Info.IsRelocatable = [&] { |
270 | if (D->isDependentType()) |
271 | return false; |
272 | |
273 | // if it is eligible for trivial relocation |
274 | if (!IsEligibleForTrivialRelocation(SemaRef&: *this, D)) |
275 | return false; |
276 | |
277 | // has the trivially_relocatable_if_eligible class-property-specifier, |
278 | if (D->hasAttr<TriviallyRelocatableAttr>()) |
279 | return true; |
280 | |
281 | // is a union with no user-declared special member functions, or |
282 | if (IsUnion()) |
283 | return true; |
284 | |
285 | // is default-movable. |
286 | return IsDefaultMovable(); |
287 | }(); |
288 | |
289 | Info.IsReplaceable = [&] { |
290 | if (D->isDependentType()) |
291 | return false; |
292 | |
293 | // A class C is a replaceable class if it is eligible for replacement |
294 | if (!IsEligibleForReplacement(SemaRef&: *this, D)) |
295 | return false; |
296 | |
297 | // has the replaceable_if_eligible class-property-specifier |
298 | if (D->hasAttr<ReplaceableAttr>()) |
299 | return HasSuitableSMP(); |
300 | |
301 | // is a union with no user-declared special member functions, or |
302 | if (IsUnion()) |
303 | return HasSuitableSMP(); |
304 | |
305 | // is default-movable. |
306 | return IsDefaultMovable(); |
307 | }(); |
308 | |
309 | return Info; |
310 | } |
311 | |
312 | bool Sema::IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD) { |
313 | if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info = |
314 | getASTContext().getRelocationInfoForCXXRecord(&RD)) |
315 | return Info->IsRelocatable; |
316 | ASTContext::CXXRecordDeclRelocationInfo Info = |
317 | CheckCXX2CRelocatableAndReplaceable(D: &RD); |
318 | getASTContext().setRelocationInfoForCXXRecord(&RD, Info); |
319 | return Info.IsRelocatable; |
320 | } |
321 | |
322 | bool Sema::IsCXXTriviallyRelocatableType(QualType Type) { |
323 | QualType BaseElementType = getASTContext().getBaseElementType(QT: Type); |
324 | |
325 | if (Type->isVariableArrayType()) |
326 | return false; |
327 | |
328 | if (BaseElementType.hasNonTrivialObjCLifetime()) |
329 | return false; |
330 | |
331 | if (BaseElementType->isIncompleteType()) |
332 | return false; |
333 | |
334 | if (Context.containsNonRelocatablePointerAuth(T: Type)) |
335 | return false; |
336 | |
337 | if (BaseElementType->isScalarType() || BaseElementType->isVectorType()) |
338 | return true; |
339 | |
340 | if (const auto *RD = BaseElementType->getAsCXXRecordDecl()) |
341 | return IsCXXTriviallyRelocatableType(RD: *RD); |
342 | |
343 | return false; |
344 | } |
345 | |
346 | static bool IsCXXReplaceableType(Sema &S, const CXXRecordDecl *RD) { |
347 | if (std::optional<ASTContext::CXXRecordDeclRelocationInfo> Info = |
348 | S.getASTContext().getRelocationInfoForCXXRecord(RD)) |
349 | return Info->IsReplaceable; |
350 | ASTContext::CXXRecordDeclRelocationInfo Info = |
351 | S.CheckCXX2CRelocatableAndReplaceable(D: RD); |
352 | S.getASTContext().setRelocationInfoForCXXRecord(RD, Info); |
353 | return Info.IsReplaceable; |
354 | } |
355 | |
356 | bool Sema::IsCXXReplaceableType(QualType Type) { |
357 | if (Type.isConstQualified() || Type.isVolatileQualified()) |
358 | return false; |
359 | |
360 | if (Type->isVariableArrayType()) |
361 | return false; |
362 | |
363 | QualType BaseElementType = |
364 | getASTContext().getBaseElementType(QT: Type.getUnqualifiedType()); |
365 | if (BaseElementType->isIncompleteType()) |
366 | return false; |
367 | if (BaseElementType->isScalarType()) |
368 | return true; |
369 | if (const auto *RD = BaseElementType->getAsCXXRecordDecl()) |
370 | return ::IsCXXReplaceableType(S&: *this, RD); |
371 | return false; |
372 | } |
373 | |
374 | /// Checks that type T is not a VLA. |
375 | /// |
376 | /// @returns @c true if @p T is VLA and a diagnostic was emitted, |
377 | /// @c false otherwise. |
378 | static bool DiagnoseVLAInCXXTypeTrait(Sema &S, const TypeSourceInfo *T, |
379 | clang::tok::TokenKind TypeTraitID) { |
380 | if (!T->getType()->isVariableArrayType()) |
381 | return false; |
382 | |
383 | S.Diag(Loc: T->getTypeLoc().getBeginLoc(), DiagID: diag::err_vla_unsupported) |
384 | << 1 << TypeTraitID; |
385 | return true; |
386 | } |
387 | |
388 | /// Checks that type T is not an atomic type (_Atomic). |
389 | /// |
390 | /// @returns @c true if @p T is VLA and a diagnostic was emitted, |
391 | /// @c false otherwise. |
392 | static bool DiagnoseAtomicInCXXTypeTrait(Sema &S, const TypeSourceInfo *T, |
393 | clang::tok::TokenKind TypeTraitID) { |
394 | if (!T->getType()->isAtomicType()) |
395 | return false; |
396 | |
397 | S.Diag(Loc: T->getTypeLoc().getBeginLoc(), DiagID: diag::err_atomic_unsupported) |
398 | << TypeTraitID; |
399 | return true; |
400 | } |
401 | |
402 | /// Check the completeness of a type in a unary type trait. |
403 | /// |
404 | /// If the particular type trait requires a complete type, tries to complete |
405 | /// it. If completing the type fails, a diagnostic is emitted and false |
406 | /// returned. If completing the type succeeds or no completion was required, |
407 | /// returns true. |
408 | static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, |
409 | SourceLocation Loc, |
410 | QualType ArgTy) { |
411 | // C++0x [meta.unary.prop]p3: |
412 | // For all of the class templates X declared in this Clause, instantiating |
413 | // that template with a template argument that is a class template |
414 | // specialization may result in the implicit instantiation of the template |
415 | // argument if and only if the semantics of X require that the argument |
416 | // must be a complete type. |
417 | // We apply this rule to all the type trait expressions used to implement |
418 | // these class templates. We also try to follow any GCC documented behavior |
419 | // in these expressions to ensure portability of standard libraries. |
420 | switch (UTT) { |
421 | default: |
422 | llvm_unreachable("not a UTT" ); |
423 | // is_complete_type somewhat obviously cannot require a complete type. |
424 | case UTT_IsCompleteType: |
425 | // Fall-through |
426 | |
427 | // These traits are modeled on the type predicates in C++0x |
428 | // [meta.unary.cat] and [meta.unary.comp]. They are not specified as |
429 | // requiring a complete type, as whether or not they return true cannot be |
430 | // impacted by the completeness of the type. |
431 | case UTT_IsVoid: |
432 | case UTT_IsIntegral: |
433 | case UTT_IsFloatingPoint: |
434 | case UTT_IsArray: |
435 | case UTT_IsBoundedArray: |
436 | case UTT_IsPointer: |
437 | case UTT_IsLvalueReference: |
438 | case UTT_IsRvalueReference: |
439 | case UTT_IsMemberFunctionPointer: |
440 | case UTT_IsMemberObjectPointer: |
441 | case UTT_IsEnum: |
442 | case UTT_IsScopedEnum: |
443 | case UTT_IsUnion: |
444 | case UTT_IsClass: |
445 | case UTT_IsFunction: |
446 | case UTT_IsReference: |
447 | case UTT_IsArithmetic: |
448 | case UTT_IsFundamental: |
449 | case UTT_IsObject: |
450 | case UTT_IsScalar: |
451 | case UTT_IsCompound: |
452 | case UTT_IsMemberPointer: |
453 | case UTT_IsTypedResourceElementCompatible: |
454 | // Fall-through |
455 | |
456 | // These traits are modeled on type predicates in C++0x [meta.unary.prop] |
457 | // which requires some of its traits to have the complete type. However, |
458 | // the completeness of the type cannot impact these traits' semantics, and |
459 | // so they don't require it. This matches the comments on these traits in |
460 | // Table 49. |
461 | case UTT_IsConst: |
462 | case UTT_IsVolatile: |
463 | case UTT_IsSigned: |
464 | case UTT_IsUnboundedArray: |
465 | case UTT_IsUnsigned: |
466 | |
467 | // This type trait always returns false, checking the type is moot. |
468 | case UTT_IsInterfaceClass: |
469 | return true; |
470 | |
471 | // We diagnose incomplete class types later. |
472 | case UTT_StructuredBindingSize: |
473 | return true; |
474 | |
475 | // C++14 [meta.unary.prop]: |
476 | // If T is a non-union class type, T shall be a complete type. |
477 | case UTT_IsEmpty: |
478 | case UTT_IsPolymorphic: |
479 | case UTT_IsAbstract: |
480 | if (const auto *RD = ArgTy->getAsCXXRecordDecl()) |
481 | if (!RD->isUnion()) |
482 | return !S.RequireCompleteType( |
483 | Loc, T: ArgTy, DiagID: diag::err_incomplete_type_used_in_type_trait_expr); |
484 | return true; |
485 | |
486 | // C++14 [meta.unary.prop]: |
487 | // If T is a class type, T shall be a complete type. |
488 | case UTT_IsFinal: |
489 | case UTT_IsSealed: |
490 | if (ArgTy->getAsCXXRecordDecl()) |
491 | return !S.RequireCompleteType( |
492 | Loc, T: ArgTy, DiagID: diag::err_incomplete_type_used_in_type_trait_expr); |
493 | return true; |
494 | |
495 | // LWG3823: T shall be an array type, a complete type, or cv void. |
496 | case UTT_IsAggregate: |
497 | case UTT_IsImplicitLifetime: |
498 | if (ArgTy->isArrayType() || ArgTy->isVoidType()) |
499 | return true; |
500 | |
501 | return !S.RequireCompleteType( |
502 | Loc, T: ArgTy, DiagID: diag::err_incomplete_type_used_in_type_trait_expr); |
503 | |
504 | // has_unique_object_representations<T> |
505 | // remove_all_extents_t<T> shall be a complete type or cv void (LWG4113). |
506 | case UTT_HasUniqueObjectRepresentations: |
507 | ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); |
508 | if (ArgTy->isVoidType()) |
509 | return true; |
510 | return !S.RequireCompleteType( |
511 | Loc, T: ArgTy, DiagID: diag::err_incomplete_type_used_in_type_trait_expr); |
512 | |
513 | // C++1z [meta.unary.prop]: |
514 | // remove_all_extents_t<T> shall be a complete type or cv void. |
515 | case UTT_IsTrivial: |
516 | case UTT_IsTriviallyCopyable: |
517 | case UTT_IsStandardLayout: |
518 | case UTT_IsPOD: |
519 | case UTT_IsLiteral: |
520 | case UTT_IsBitwiseCloneable: |
521 | // By analogy, is_trivially_relocatable and is_trivially_equality_comparable |
522 | // impose the same constraints. |
523 | case UTT_IsTriviallyRelocatable: |
524 | case UTT_IsTriviallyEqualityComparable: |
525 | case UTT_IsCppTriviallyRelocatable: |
526 | case UTT_IsReplaceable: |
527 | case UTT_CanPassInRegs: |
528 | // Per the GCC type traits documentation, T shall be a complete type, cv void, |
529 | // or an array of unknown bound. But GCC actually imposes the same constraints |
530 | // as above. |
531 | case UTT_HasNothrowAssign: |
532 | case UTT_HasNothrowMoveAssign: |
533 | case UTT_HasNothrowConstructor: |
534 | case UTT_HasNothrowCopy: |
535 | case UTT_HasTrivialAssign: |
536 | case UTT_HasTrivialMoveAssign: |
537 | case UTT_HasTrivialDefaultConstructor: |
538 | case UTT_HasTrivialMoveConstructor: |
539 | case UTT_HasTrivialCopy: |
540 | case UTT_HasTrivialDestructor: |
541 | case UTT_HasVirtualDestructor: |
542 | ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); |
543 | [[fallthrough]]; |
544 | // C++1z [meta.unary.prop]: |
545 | // T shall be a complete type, cv void, or an array of unknown bound. |
546 | case UTT_IsDestructible: |
547 | case UTT_IsNothrowDestructible: |
548 | case UTT_IsTriviallyDestructible: |
549 | case UTT_IsIntangibleType: |
550 | if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) |
551 | return true; |
552 | |
553 | return !S.RequireCompleteType( |
554 | Loc, T: ArgTy, DiagID: diag::err_incomplete_type_used_in_type_trait_expr); |
555 | } |
556 | } |
557 | |
558 | static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, |
559 | Sema &Self, SourceLocation KeyLoc, ASTContext &C, |
560 | bool (CXXRecordDecl::*HasTrivial)() const, |
561 | bool (CXXRecordDecl::*HasNonTrivial)() const, |
562 | bool (CXXMethodDecl::*IsDesiredOp)() const) { |
563 | CXXRecordDecl *RD = cast<CXXRecordDecl>(Val: RT->getDecl()); |
564 | if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) |
565 | return true; |
566 | |
567 | DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op); |
568 | DeclarationNameInfo NameInfo(Name, KeyLoc); |
569 | LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName); |
570 | if (Self.LookupQualifiedName(R&: Res, LookupCtx: RD)) { |
571 | bool FoundOperator = false; |
572 | Res.suppressDiagnostics(); |
573 | for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); |
574 | Op != OpEnd; ++Op) { |
575 | if (isa<FunctionTemplateDecl>(Val: *Op)) |
576 | continue; |
577 | |
578 | CXXMethodDecl *Operator = cast<CXXMethodDecl>(Val: *Op); |
579 | if ((Operator->*IsDesiredOp)()) { |
580 | FoundOperator = true; |
581 | auto *CPT = Operator->getType()->castAs<FunctionProtoType>(); |
582 | CPT = Self.ResolveExceptionSpec(Loc: KeyLoc, FPT: CPT); |
583 | if (!CPT || !CPT->isNothrow()) |
584 | return false; |
585 | } |
586 | } |
587 | return FoundOperator; |
588 | } |
589 | return false; |
590 | } |
591 | |
592 | static bool HasNonDeletedDefaultedEqualityComparison(Sema &S, |
593 | const CXXRecordDecl *Decl, |
594 | SourceLocation KeyLoc) { |
595 | if (Decl->isUnion()) |
596 | return false; |
597 | if (Decl->isLambda()) |
598 | return Decl->isCapturelessLambda(); |
599 | |
600 | { |
601 | EnterExpressionEvaluationContext UnevaluatedContext( |
602 | S, Sema::ExpressionEvaluationContext::Unevaluated); |
603 | Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); |
604 | Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); |
605 | |
606 | // const ClassT& obj; |
607 | OpaqueValueExpr Operand( |
608 | KeyLoc, |
609 | Decl->getTypeForDecl()->getCanonicalTypeUnqualified().withConst(), |
610 | ExprValueKind::VK_LValue); |
611 | UnresolvedSet<16> Functions; |
612 | // obj == obj; |
613 | S.LookupBinOp(S: S.TUScope, OpLoc: {}, Opc: BinaryOperatorKind::BO_EQ, Functions); |
614 | |
615 | auto Result = S.CreateOverloadedBinOp(OpLoc: KeyLoc, Opc: BinaryOperatorKind::BO_EQ, |
616 | Fns: Functions, LHS: &Operand, RHS: &Operand); |
617 | if (Result.isInvalid() || SFINAE.hasErrorOccurred()) |
618 | return false; |
619 | |
620 | const auto *CallExpr = dyn_cast<CXXOperatorCallExpr>(Val: Result.get()); |
621 | if (!CallExpr) |
622 | return false; |
623 | const auto *Callee = CallExpr->getDirectCallee(); |
624 | auto ParamT = Callee->getParamDecl(i: 0)->getType(); |
625 | if (!Callee->isDefaulted()) |
626 | return false; |
627 | if (!ParamT->isReferenceType() && !Decl->isTriviallyCopyable()) |
628 | return false; |
629 | if (ParamT.getNonReferenceType()->getUnqualifiedDesugaredType() != |
630 | Decl->getTypeForDecl()) |
631 | return false; |
632 | } |
633 | |
634 | return llvm::all_of(Range: Decl->bases(), |
635 | P: [&](const CXXBaseSpecifier &BS) { |
636 | if (const auto *RD = BS.getType()->getAsCXXRecordDecl()) |
637 | return HasNonDeletedDefaultedEqualityComparison( |
638 | S, Decl: RD, KeyLoc); |
639 | return true; |
640 | }) && |
641 | llvm::all_of(Range: Decl->fields(), P: [&](const FieldDecl *FD) { |
642 | auto Type = FD->getType(); |
643 | if (Type->isArrayType()) |
644 | Type = Type->getBaseElementTypeUnsafe() |
645 | ->getCanonicalTypeUnqualified(); |
646 | |
647 | if (Type->isReferenceType() || Type->isEnumeralType()) |
648 | return false; |
649 | if (const auto *RD = Type->getAsCXXRecordDecl()) |
650 | return HasNonDeletedDefaultedEqualityComparison(S, Decl: RD, KeyLoc); |
651 | return true; |
652 | }); |
653 | } |
654 | |
655 | static bool isTriviallyEqualityComparableType(Sema &S, QualType Type, |
656 | SourceLocation KeyLoc) { |
657 | QualType CanonicalType = Type.getCanonicalType(); |
658 | if (CanonicalType->isIncompleteType() || CanonicalType->isDependentType() || |
659 | CanonicalType->isEnumeralType() || CanonicalType->isArrayType()) |
660 | return false; |
661 | |
662 | if (const auto *RD = CanonicalType->getAsCXXRecordDecl()) { |
663 | if (!HasNonDeletedDefaultedEqualityComparison(S, Decl: RD, KeyLoc)) |
664 | return false; |
665 | } |
666 | |
667 | return S.getASTContext().hasUniqueObjectRepresentations( |
668 | Ty: CanonicalType, /*CheckIfTriviallyCopyable=*/false); |
669 | } |
670 | |
671 | static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) { |
672 | QualType BaseElementType = SemaRef.getASTContext().getBaseElementType(QT: T); |
673 | |
674 | if (BaseElementType->isIncompleteType()) |
675 | return false; |
676 | if (!BaseElementType->isObjectType()) |
677 | return false; |
678 | |
679 | // The deprecated __builtin_is_trivially_relocatable does not have |
680 | // an equivalent to __builtin_trivially_relocate, so there is no |
681 | // safe way to use it if there are any address discriminated values. |
682 | if (SemaRef.getASTContext().containsAddressDiscriminatedPointerAuth(T)) |
683 | return false; |
684 | |
685 | if (const auto *RD = BaseElementType->getAsCXXRecordDecl(); |
686 | RD && !RD->isPolymorphic() && SemaRef.IsCXXTriviallyRelocatableType(RD: *RD)) |
687 | return true; |
688 | |
689 | if (const auto *RD = BaseElementType->getAsRecordDecl()) |
690 | return RD->canPassInRegisters(); |
691 | |
692 | if (BaseElementType.isTriviallyCopyableType(Context: SemaRef.getASTContext())) |
693 | return true; |
694 | |
695 | switch (T.isNonTrivialToPrimitiveDestructiveMove()) { |
696 | case QualType::PCK_Trivial: |
697 | return !T.isDestructedType(); |
698 | case QualType::PCK_ARCStrong: |
699 | return true; |
700 | default: |
701 | return false; |
702 | } |
703 | } |
704 | |
705 | static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, |
706 | SourceLocation KeyLoc, |
707 | TypeSourceInfo *TInfo) { |
708 | QualType T = TInfo->getType(); |
709 | assert(!T->isDependentType() && "Cannot evaluate traits of dependent type" ); |
710 | |
711 | ASTContext &C = Self.Context; |
712 | switch (UTT) { |
713 | default: |
714 | llvm_unreachable("not a UTT" ); |
715 | // Type trait expressions corresponding to the primary type category |
716 | // predicates in C++0x [meta.unary.cat]. |
717 | case UTT_IsVoid: |
718 | return T->isVoidType(); |
719 | case UTT_IsIntegral: |
720 | return T->isIntegralType(Ctx: C); |
721 | case UTT_IsFloatingPoint: |
722 | return T->isFloatingType(); |
723 | case UTT_IsArray: |
724 | // Zero-sized arrays aren't considered arrays in partial specializations, |
725 | // so __is_array shouldn't consider them arrays either. |
726 | if (const auto *CAT = C.getAsConstantArrayType(T)) |
727 | return CAT->getSize() != 0; |
728 | return T->isArrayType(); |
729 | case UTT_IsBoundedArray: |
730 | if (DiagnoseVLAInCXXTypeTrait(S&: Self, T: TInfo, TypeTraitID: tok::kw___is_bounded_array)) |
731 | return false; |
732 | // Zero-sized arrays aren't considered arrays in partial specializations, |
733 | // so __is_bounded_array shouldn't consider them arrays either. |
734 | if (const auto *CAT = C.getAsConstantArrayType(T)) |
735 | return CAT->getSize() != 0; |
736 | return T->isArrayType() && !T->isIncompleteArrayType(); |
737 | case UTT_IsUnboundedArray: |
738 | if (DiagnoseVLAInCXXTypeTrait(S&: Self, T: TInfo, TypeTraitID: tok::kw___is_unbounded_array)) |
739 | return false; |
740 | return T->isIncompleteArrayType(); |
741 | case UTT_IsPointer: |
742 | return T->isAnyPointerType(); |
743 | case UTT_IsLvalueReference: |
744 | return T->isLValueReferenceType(); |
745 | case UTT_IsRvalueReference: |
746 | return T->isRValueReferenceType(); |
747 | case UTT_IsMemberFunctionPointer: |
748 | return T->isMemberFunctionPointerType(); |
749 | case UTT_IsMemberObjectPointer: |
750 | return T->isMemberDataPointerType(); |
751 | case UTT_IsEnum: |
752 | return T->isEnumeralType(); |
753 | case UTT_IsScopedEnum: |
754 | return T->isScopedEnumeralType(); |
755 | case UTT_IsUnion: |
756 | return T->isUnionType(); |
757 | case UTT_IsClass: |
758 | return T->isClassType() || T->isStructureType() || T->isInterfaceType(); |
759 | case UTT_IsFunction: |
760 | return T->isFunctionType(); |
761 | |
762 | // Type trait expressions which correspond to the convenient composition |
763 | // predicates in C++0x [meta.unary.comp]. |
764 | case UTT_IsReference: |
765 | return T->isReferenceType(); |
766 | case UTT_IsArithmetic: |
767 | return T->isArithmeticType() && !T->isEnumeralType(); |
768 | case UTT_IsFundamental: |
769 | return T->isFundamentalType(); |
770 | case UTT_IsObject: |
771 | return T->isObjectType(); |
772 | case UTT_IsScalar: |
773 | // Note: semantic analysis depends on Objective-C lifetime types to be |
774 | // considered scalar types. However, such types do not actually behave |
775 | // like scalar types at run time (since they may require retain/release |
776 | // operations), so we report them as non-scalar. |
777 | if (T->isObjCLifetimeType()) { |
778 | switch (T.getObjCLifetime()) { |
779 | case Qualifiers::OCL_None: |
780 | case Qualifiers::OCL_ExplicitNone: |
781 | return true; |
782 | |
783 | case Qualifiers::OCL_Strong: |
784 | case Qualifiers::OCL_Weak: |
785 | case Qualifiers::OCL_Autoreleasing: |
786 | return false; |
787 | } |
788 | } |
789 | |
790 | return T->isScalarType(); |
791 | case UTT_IsCompound: |
792 | return T->isCompoundType(); |
793 | case UTT_IsMemberPointer: |
794 | return T->isMemberPointerType(); |
795 | |
796 | // Type trait expressions which correspond to the type property predicates |
797 | // in C++0x [meta.unary.prop]. |
798 | case UTT_IsConst: |
799 | return T.isConstQualified(); |
800 | case UTT_IsVolatile: |
801 | return T.isVolatileQualified(); |
802 | case UTT_IsTrivial: |
803 | return T.isTrivialType(Context: C); |
804 | case UTT_IsTriviallyCopyable: |
805 | return T.isTriviallyCopyableType(Context: C); |
806 | case UTT_IsStandardLayout: |
807 | return T->isStandardLayoutType(); |
808 | case UTT_IsPOD: |
809 | return T.isPODType(Context: C); |
810 | case UTT_IsLiteral: |
811 | return T->isLiteralType(Ctx: C); |
812 | case UTT_IsEmpty: |
813 | if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
814 | return !RD->isUnion() && RD->isEmpty(); |
815 | return false; |
816 | case UTT_IsPolymorphic: |
817 | if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
818 | return !RD->isUnion() && RD->isPolymorphic(); |
819 | return false; |
820 | case UTT_IsAbstract: |
821 | if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
822 | return !RD->isUnion() && RD->isAbstract(); |
823 | return false; |
824 | case UTT_IsAggregate: |
825 | // Report vector extensions and complex types as aggregates because they |
826 | // support aggregate initialization. GCC mirrors this behavior for vectors |
827 | // but not _Complex. |
828 | return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() || |
829 | T->isAnyComplexType(); |
830 | // __is_interface_class only returns true when CL is invoked in /CLR mode and |
831 | // even then only when it is used with the 'interface struct ...' syntax |
832 | // Clang doesn't support /CLR which makes this type trait moot. |
833 | case UTT_IsInterfaceClass: |
834 | return false; |
835 | case UTT_IsFinal: |
836 | case UTT_IsSealed: |
837 | if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
838 | return RD->hasAttr<FinalAttr>(); |
839 | return false; |
840 | case UTT_IsSigned: |
841 | // Enum types should always return false. |
842 | // Floating points should always return true. |
843 | return T->isFloatingType() || |
844 | (T->isSignedIntegerType() && !T->isEnumeralType()); |
845 | case UTT_IsUnsigned: |
846 | // Enum types should always return false. |
847 | return T->isUnsignedIntegerType() && !T->isEnumeralType(); |
848 | |
849 | // Type trait expressions which query classes regarding their construction, |
850 | // destruction, and copying. Rather than being based directly on the |
851 | // related type predicates in the standard, they are specified by both |
852 | // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those |
853 | // specifications. |
854 | // |
855 | // 1: http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html |
856 | // 2: |
857 | // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index |
858 | // |
859 | // Note that these builtins do not behave as documented in g++: if a class |
860 | // has both a trivial and a non-trivial special member of a particular kind, |
861 | // they return false! For now, we emulate this behavior. |
862 | // FIXME: This appears to be a g++ bug: more complex cases reveal that it |
863 | // does not correctly compute triviality in the presence of multiple special |
864 | // members of the same kind. Revisit this once the g++ bug is fixed. |
865 | case UTT_HasTrivialDefaultConstructor: |
866 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: |
867 | // If __is_pod (type) is true then the trait is true, else if type is |
868 | // a cv class or union type (or array thereof) with a trivial default |
869 | // constructor ([class.ctor]) then the trait is true, else it is false. |
870 | if (T.isPODType(Context: C)) |
871 | return true; |
872 | if (CXXRecordDecl *RD = C.getBaseElementType(QT: T)->getAsCXXRecordDecl()) |
873 | return RD->hasTrivialDefaultConstructor() && |
874 | !RD->hasNonTrivialDefaultConstructor(); |
875 | return false; |
876 | case UTT_HasTrivialMoveConstructor: |
877 | // This trait is implemented by MSVC 2012 and needed to parse the |
878 | // standard library headers. Specifically this is used as the logic |
879 | // behind std::is_trivially_move_constructible (20.9.4.3). |
880 | if (T.isPODType(Context: C)) |
881 | return true; |
882 | if (CXXRecordDecl *RD = C.getBaseElementType(QT: T)->getAsCXXRecordDecl()) |
883 | return RD->hasTrivialMoveConstructor() && |
884 | !RD->hasNonTrivialMoveConstructor(); |
885 | return false; |
886 | case UTT_HasTrivialCopy: |
887 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: |
888 | // If __is_pod (type) is true or type is a reference type then |
889 | // the trait is true, else if type is a cv class or union type |
890 | // with a trivial copy constructor ([class.copy]) then the trait |
891 | // is true, else it is false. |
892 | if (T.isPODType(Context: C) || T->isReferenceType()) |
893 | return true; |
894 | if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
895 | return RD->hasTrivialCopyConstructor() && |
896 | !RD->hasNonTrivialCopyConstructor(); |
897 | return false; |
898 | case UTT_HasTrivialMoveAssign: |
899 | // This trait is implemented by MSVC 2012 and needed to parse the |
900 | // standard library headers. Specifically it is used as the logic |
901 | // behind std::is_trivially_move_assignable (20.9.4.3) |
902 | if (T.isPODType(Context: C)) |
903 | return true; |
904 | if (CXXRecordDecl *RD = C.getBaseElementType(QT: T)->getAsCXXRecordDecl()) |
905 | return RD->hasTrivialMoveAssignment() && |
906 | !RD->hasNonTrivialMoveAssignment(); |
907 | return false; |
908 | case UTT_HasTrivialAssign: |
909 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: |
910 | // If type is const qualified or is a reference type then the |
911 | // trait is false. Otherwise if __is_pod (type) is true then the |
912 | // trait is true, else if type is a cv class or union type with |
913 | // a trivial copy assignment ([class.copy]) then the trait is |
914 | // true, else it is false. |
915 | // Note: the const and reference restrictions are interesting, |
916 | // given that const and reference members don't prevent a class |
917 | // from having a trivial copy assignment operator (but do cause |
918 | // errors if the copy assignment operator is actually used, q.v. |
919 | // [class.copy]p12). |
920 | |
921 | if (T.isConstQualified()) |
922 | return false; |
923 | if (T.isPODType(Context: C)) |
924 | return true; |
925 | if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
926 | return RD->hasTrivialCopyAssignment() && |
927 | !RD->hasNonTrivialCopyAssignment(); |
928 | return false; |
929 | case UTT_IsDestructible: |
930 | case UTT_IsTriviallyDestructible: |
931 | case UTT_IsNothrowDestructible: |
932 | // C++14 [meta.unary.prop]: |
933 | // For reference types, is_destructible<T>::value is true. |
934 | if (T->isReferenceType()) |
935 | return true; |
936 | |
937 | // Objective-C++ ARC: autorelease types don't require destruction. |
938 | if (T->isObjCLifetimeType() && |
939 | T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) |
940 | return true; |
941 | |
942 | // C++14 [meta.unary.prop]: |
943 | // For incomplete types and function types, is_destructible<T>::value is |
944 | // false. |
945 | if (T->isIncompleteType() || T->isFunctionType()) |
946 | return false; |
947 | |
948 | // A type that requires destruction (via a non-trivial destructor or ARC |
949 | // lifetime semantics) is not trivially-destructible. |
950 | if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType()) |
951 | return false; |
952 | |
953 | // C++14 [meta.unary.prop]: |
954 | // For object types and given U equal to remove_all_extents_t<T>, if the |
955 | // expression std::declval<U&>().~U() is well-formed when treated as an |
956 | // unevaluated operand (Clause 5), then is_destructible<T>::value is true |
957 | if (auto *RD = C.getBaseElementType(QT: T)->getAsCXXRecordDecl()) { |
958 | CXXDestructorDecl *Destructor = Self.LookupDestructor(Class: RD); |
959 | if (!Destructor) |
960 | return false; |
961 | // C++14 [dcl.fct.def.delete]p2: |
962 | // A program that refers to a deleted function implicitly or |
963 | // explicitly, other than to declare it, is ill-formed. |
964 | if (Destructor->isDeleted()) |
965 | return false; |
966 | if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public) |
967 | return false; |
968 | if (UTT == UTT_IsNothrowDestructible) { |
969 | auto *CPT = Destructor->getType()->castAs<FunctionProtoType>(); |
970 | CPT = Self.ResolveExceptionSpec(Loc: KeyLoc, FPT: CPT); |
971 | if (!CPT || !CPT->isNothrow()) |
972 | return false; |
973 | } |
974 | } |
975 | return true; |
976 | |
977 | case UTT_HasTrivialDestructor: |
978 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html |
979 | // If __is_pod (type) is true or type is a reference type |
980 | // then the trait is true, else if type is a cv class or union |
981 | // type (or array thereof) with a trivial destructor |
982 | // ([class.dtor]) then the trait is true, else it is |
983 | // false. |
984 | if (T.isPODType(Context: C) || T->isReferenceType()) |
985 | return true; |
986 | |
987 | // Objective-C++ ARC: autorelease types don't require destruction. |
988 | if (T->isObjCLifetimeType() && |
989 | T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) |
990 | return true; |
991 | |
992 | if (CXXRecordDecl *RD = C.getBaseElementType(QT: T)->getAsCXXRecordDecl()) |
993 | return RD->hasTrivialDestructor(); |
994 | return false; |
995 | // TODO: Propagate nothrowness for implicitly declared special members. |
996 | case UTT_HasNothrowAssign: |
997 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: |
998 | // If type is const qualified or is a reference type then the |
999 | // trait is false. Otherwise if __has_trivial_assign (type) |
1000 | // is true then the trait is true, else if type is a cv class |
1001 | // or union type with copy assignment operators that are known |
1002 | // not to throw an exception then the trait is true, else it is |
1003 | // false. |
1004 | if (C.getBaseElementType(QT: T).isConstQualified()) |
1005 | return false; |
1006 | if (T->isReferenceType()) |
1007 | return false; |
1008 | if (T.isPODType(Context: C) || T->isObjCLifetimeType()) |
1009 | return true; |
1010 | |
1011 | if (const RecordType *RT = T->getAs<RecordType>()) |
1012 | return HasNoThrowOperator(RT, Op: OO_Equal, Self, KeyLoc, C, |
1013 | HasTrivial: &CXXRecordDecl::hasTrivialCopyAssignment, |
1014 | HasNonTrivial: &CXXRecordDecl::hasNonTrivialCopyAssignment, |
1015 | IsDesiredOp: &CXXMethodDecl::isCopyAssignmentOperator); |
1016 | return false; |
1017 | case UTT_HasNothrowMoveAssign: |
1018 | // This trait is implemented by MSVC 2012 and needed to parse the |
1019 | // standard library headers. Specifically this is used as the logic |
1020 | // behind std::is_nothrow_move_assignable (20.9.4.3). |
1021 | if (T.isPODType(Context: C)) |
1022 | return true; |
1023 | |
1024 | if (const RecordType *RT = C.getBaseElementType(QT: T)->getAs<RecordType>()) |
1025 | return HasNoThrowOperator(RT, Op: OO_Equal, Self, KeyLoc, C, |
1026 | HasTrivial: &CXXRecordDecl::hasTrivialMoveAssignment, |
1027 | HasNonTrivial: &CXXRecordDecl::hasNonTrivialMoveAssignment, |
1028 | IsDesiredOp: &CXXMethodDecl::isMoveAssignmentOperator); |
1029 | return false; |
1030 | case UTT_HasNothrowCopy: |
1031 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: |
1032 | // If __has_trivial_copy (type) is true then the trait is true, else |
1033 | // if type is a cv class or union type with copy constructors that are |
1034 | // known not to throw an exception then the trait is true, else it is |
1035 | // false. |
1036 | if (T.isPODType(Context: C) || T->isReferenceType() || T->isObjCLifetimeType()) |
1037 | return true; |
1038 | if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { |
1039 | if (RD->hasTrivialCopyConstructor() && |
1040 | !RD->hasNonTrivialCopyConstructor()) |
1041 | return true; |
1042 | |
1043 | bool FoundConstructor = false; |
1044 | unsigned FoundTQs; |
1045 | for (const auto *ND : Self.LookupConstructors(Class: RD)) { |
1046 | // A template constructor is never a copy constructor. |
1047 | // FIXME: However, it may actually be selected at the actual overload |
1048 | // resolution point. |
1049 | if (isa<FunctionTemplateDecl>(Val: ND->getUnderlyingDecl())) |
1050 | continue; |
1051 | // UsingDecl itself is not a constructor |
1052 | if (isa<UsingDecl>(Val: ND)) |
1053 | continue; |
1054 | auto *Constructor = cast<CXXConstructorDecl>(Val: ND->getUnderlyingDecl()); |
1055 | if (Constructor->isCopyConstructor(TypeQuals&: FoundTQs)) { |
1056 | FoundConstructor = true; |
1057 | auto *CPT = Constructor->getType()->castAs<FunctionProtoType>(); |
1058 | CPT = Self.ResolveExceptionSpec(Loc: KeyLoc, FPT: CPT); |
1059 | if (!CPT) |
1060 | return false; |
1061 | // TODO: check whether evaluating default arguments can throw. |
1062 | // For now, we'll be conservative and assume that they can throw. |
1063 | if (!CPT->isNothrow() || CPT->getNumParams() > 1) |
1064 | return false; |
1065 | } |
1066 | } |
1067 | |
1068 | return FoundConstructor; |
1069 | } |
1070 | return false; |
1071 | case UTT_HasNothrowConstructor: |
1072 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html |
1073 | // If __has_trivial_constructor (type) is true then the trait is |
1074 | // true, else if type is a cv class or union type (or array |
1075 | // thereof) with a default constructor that is known not to |
1076 | // throw an exception then the trait is true, else it is false. |
1077 | if (T.isPODType(Context: C) || T->isObjCLifetimeType()) |
1078 | return true; |
1079 | if (CXXRecordDecl *RD = C.getBaseElementType(QT: T)->getAsCXXRecordDecl()) { |
1080 | if (RD->hasTrivialDefaultConstructor() && |
1081 | !RD->hasNonTrivialDefaultConstructor()) |
1082 | return true; |
1083 | |
1084 | bool FoundConstructor = false; |
1085 | for (const auto *ND : Self.LookupConstructors(Class: RD)) { |
1086 | // FIXME: In C++0x, a constructor template can be a default constructor. |
1087 | if (isa<FunctionTemplateDecl>(Val: ND->getUnderlyingDecl())) |
1088 | continue; |
1089 | // UsingDecl itself is not a constructor |
1090 | if (isa<UsingDecl>(Val: ND)) |
1091 | continue; |
1092 | auto *Constructor = cast<CXXConstructorDecl>(Val: ND->getUnderlyingDecl()); |
1093 | if (Constructor->isDefaultConstructor()) { |
1094 | FoundConstructor = true; |
1095 | auto *CPT = Constructor->getType()->castAs<FunctionProtoType>(); |
1096 | CPT = Self.ResolveExceptionSpec(Loc: KeyLoc, FPT: CPT); |
1097 | if (!CPT) |
1098 | return false; |
1099 | // FIXME: check whether evaluating default arguments can throw. |
1100 | // For now, we'll be conservative and assume that they can throw. |
1101 | if (!CPT->isNothrow() || CPT->getNumParams() > 0) |
1102 | return false; |
1103 | } |
1104 | } |
1105 | return FoundConstructor; |
1106 | } |
1107 | return false; |
1108 | case UTT_HasVirtualDestructor: |
1109 | // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: |
1110 | // If type is a class type with a virtual destructor ([class.dtor]) |
1111 | // then the trait is true, else it is false. |
1112 | if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) |
1113 | if (CXXDestructorDecl *Destructor = Self.LookupDestructor(Class: RD)) |
1114 | return Destructor->isVirtual(); |
1115 | return false; |
1116 | |
1117 | // These type trait expressions are modeled on the specifications for the |
1118 | // Embarcadero C++0x type trait functions: |
1119 | // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index |
1120 | case UTT_IsCompleteType: |
1121 | // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_): |
1122 | // Returns True if and only if T is a complete type at the point of the |
1123 | // function call. |
1124 | return !T->isIncompleteType(); |
1125 | case UTT_HasUniqueObjectRepresentations: |
1126 | return C.hasUniqueObjectRepresentations(Ty: T); |
1127 | case UTT_IsTriviallyRelocatable: |
1128 | return IsTriviallyRelocatableType(SemaRef&: Self, T); |
1129 | case UTT_IsBitwiseCloneable: |
1130 | return T.isBitwiseCloneableType(Context: C); |
1131 | case UTT_IsCppTriviallyRelocatable: |
1132 | return Self.IsCXXTriviallyRelocatableType(Type: T); |
1133 | case UTT_IsReplaceable: |
1134 | return Self.IsCXXReplaceableType(Type: T); |
1135 | case UTT_CanPassInRegs: |
1136 | if (CXXRecordDecl *RD = T->getAsCXXRecordDecl(); RD && !T.hasQualifiers()) |
1137 | return RD->canPassInRegisters(); |
1138 | Self.Diag(Loc: KeyLoc, DiagID: diag::err_builtin_pass_in_regs_non_class) << T; |
1139 | return false; |
1140 | case UTT_IsTriviallyEqualityComparable: |
1141 | return isTriviallyEqualityComparableType(S&: Self, Type: T, KeyLoc); |
1142 | case UTT_IsImplicitLifetime: { |
1143 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: TInfo, |
1144 | TypeTraitID: tok::kw___builtin_is_implicit_lifetime); |
1145 | DiagnoseAtomicInCXXTypeTrait(S&: Self, T: TInfo, |
1146 | TypeTraitID: tok::kw___builtin_is_implicit_lifetime); |
1147 | |
1148 | // [basic.types.general] p9 |
1149 | // Scalar types, implicit-lifetime class types ([class.prop]), |
1150 | // array types, and cv-qualified versions of these types |
1151 | // are collectively called implicit-lifetime types. |
1152 | QualType UnqualT = T->getCanonicalTypeUnqualified(); |
1153 | if (UnqualT->isScalarType()) |
1154 | return true; |
1155 | if (UnqualT->isArrayType() || UnqualT->isVectorType()) |
1156 | return true; |
1157 | const CXXRecordDecl *RD = UnqualT->getAsCXXRecordDecl(); |
1158 | if (!RD) |
1159 | return false; |
1160 | |
1161 | // [class.prop] p9 |
1162 | // A class S is an implicit-lifetime class if |
1163 | // - it is an aggregate whose destructor is not user-provided or |
1164 | // - it has at least one trivial eligible constructor and a trivial, |
1165 | // non-deleted destructor. |
1166 | const CXXDestructorDecl *Dtor = RD->getDestructor(); |
1167 | if (UnqualT->isAggregateType()) |
1168 | if (Dtor && !Dtor->isUserProvided()) |
1169 | return true; |
1170 | if (RD->hasTrivialDestructor() && (!Dtor || !Dtor->isDeleted())) |
1171 | if (RD->hasTrivialDefaultConstructor() || |
1172 | RD->hasTrivialCopyConstructor() || RD->hasTrivialMoveConstructor()) |
1173 | return true; |
1174 | return false; |
1175 | } |
1176 | case UTT_IsIntangibleType: |
1177 | assert(Self.getLangOpts().HLSL && "intangible types are HLSL-only feature" ); |
1178 | if (!T->isVoidType() && !T->isIncompleteArrayType()) |
1179 | if (Self.RequireCompleteType(Loc: TInfo->getTypeLoc().getBeginLoc(), T, |
1180 | DiagID: diag::err_incomplete_type)) |
1181 | return false; |
1182 | if (DiagnoseVLAInCXXTypeTrait(S&: Self, T: TInfo, |
1183 | TypeTraitID: tok::kw___builtin_hlsl_is_intangible)) |
1184 | return false; |
1185 | return T->isHLSLIntangibleType(); |
1186 | |
1187 | case UTT_IsTypedResourceElementCompatible: |
1188 | assert(Self.getLangOpts().HLSL && |
1189 | "typed resource element compatible types are an HLSL-only feature" ); |
1190 | if (T->isIncompleteType()) |
1191 | return false; |
1192 | |
1193 | return Self.HLSL().IsTypedResourceElementCompatible(T1: T); |
1194 | } |
1195 | } |
1196 | |
1197 | static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, |
1198 | const TypeSourceInfo *Lhs, |
1199 | const TypeSourceInfo *Rhs, |
1200 | SourceLocation KeyLoc); |
1201 | |
1202 | static ExprResult CheckConvertibilityForTypeTraits( |
1203 | Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs, |
1204 | SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) { |
1205 | |
1206 | QualType LhsT = Lhs->getType(); |
1207 | QualType RhsT = Rhs->getType(); |
1208 | |
1209 | // C++0x [meta.rel]p4: |
1210 | // Given the following function prototype: |
1211 | // |
1212 | // template <class T> |
1213 | // typename add_rvalue_reference<T>::type create(); |
1214 | // |
1215 | // the predicate condition for a template specialization |
1216 | // is_convertible<From, To> shall be satisfied if and only if |
1217 | // the return expression in the following code would be |
1218 | // well-formed, including any implicit conversions to the return |
1219 | // type of the function: |
1220 | // |
1221 | // To test() { |
1222 | // return create<From>(); |
1223 | // } |
1224 | // |
1225 | // Access checking is performed as if in a context unrelated to To and |
1226 | // From. Only the validity of the immediate context of the expression |
1227 | // of the return-statement (including conversions to the return type) |
1228 | // is considered. |
1229 | // |
1230 | // We model the initialization as a copy-initialization of a temporary |
1231 | // of the appropriate type, which for this expression is identical to the |
1232 | // return statement (since NRVO doesn't apply). |
1233 | |
1234 | // Functions aren't allowed to return function or array types. |
1235 | if (RhsT->isFunctionType() || RhsT->isArrayType()) |
1236 | return ExprError(); |
1237 | |
1238 | // A function definition requires a complete, non-abstract return type. |
1239 | if (!Self.isCompleteType(Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT) || |
1240 | Self.isAbstractType(Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT)) |
1241 | return ExprError(); |
1242 | |
1243 | // Compute the result of add_rvalue_reference. |
1244 | if (LhsT->isObjectType() || LhsT->isFunctionType()) |
1245 | LhsT = Self.Context.getRValueReferenceType(T: LhsT); |
1246 | |
1247 | // Build a fake source and destination for initialization. |
1248 | InitializedEntity To(InitializedEntity::InitializeTemporary(Type: RhsT)); |
1249 | Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) |
1250 | OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Context: Self.Context), |
1251 | Expr::getValueKindForType(T: LhsT)); |
1252 | InitializationKind Kind = |
1253 | InitializationKind::CreateCopy(InitLoc: KeyLoc, EqualLoc: SourceLocation()); |
1254 | |
1255 | // Perform the initialization in an unevaluated context within a SFINAE |
1256 | // trap at translation unit scope. |
1257 | EnterExpressionEvaluationContext Unevaluated( |
1258 | Self, Sema::ExpressionEvaluationContext::Unevaluated); |
1259 | Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true); |
1260 | Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); |
1261 | InitializationSequence Init(Self, To, Kind, From); |
1262 | if (Init.Failed()) |
1263 | return ExprError(); |
1264 | |
1265 | ExprResult Result = Init.Perform(S&: Self, Entity: To, Kind, Args: From); |
1266 | if (Result.isInvalid() || SFINAE.hasErrorOccurred()) |
1267 | return ExprError(); |
1268 | |
1269 | return Result; |
1270 | } |
1271 | |
1272 | static APValue EvaluateSizeTTypeTrait(Sema &S, TypeTrait Kind, |
1273 | SourceLocation KWLoc, |
1274 | ArrayRef<TypeSourceInfo *> Args, |
1275 | SourceLocation RParenLoc, |
1276 | bool IsDependent) { |
1277 | if (IsDependent) |
1278 | return APValue(); |
1279 | |
1280 | switch (Kind) { |
1281 | case TypeTrait::UTT_StructuredBindingSize: { |
1282 | QualType T = Args[0]->getType(); |
1283 | SourceRange ArgRange = Args[0]->getTypeLoc().getSourceRange(); |
1284 | UnsignedOrNone Size = |
1285 | S.GetDecompositionElementCount(DecompType: T, Loc: ArgRange.getBegin()); |
1286 | if (!Size) { |
1287 | S.Diag(Loc: KWLoc, DiagID: diag::err_arg_is_not_destructurable) << T << ArgRange; |
1288 | return APValue(); |
1289 | } |
1290 | return APValue( |
1291 | S.getASTContext().MakeIntValue(Value: *Size, Type: S.getASTContext().getSizeType())); |
1292 | break; |
1293 | } |
1294 | default: |
1295 | llvm_unreachable("Not a SizeT type trait" ); |
1296 | } |
1297 | } |
1298 | |
1299 | static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, |
1300 | SourceLocation KWLoc, |
1301 | ArrayRef<TypeSourceInfo *> Args, |
1302 | SourceLocation RParenLoc, |
1303 | bool IsDependent) { |
1304 | if (IsDependent) |
1305 | return false; |
1306 | |
1307 | if (Kind <= UTT_Last) |
1308 | return EvaluateUnaryTypeTrait(Self&: S, UTT: Kind, KeyLoc: KWLoc, TInfo: Args[0]); |
1309 | |
1310 | // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary |
1311 | // alongside the IsConstructible traits to avoid duplication. |
1312 | if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary && |
1313 | Kind != BTT_ReferenceConstructsFromTemporary && |
1314 | Kind != BTT_ReferenceConvertsFromTemporary) |
1315 | return EvaluateBinaryTypeTrait(Self&: S, BTT: Kind, Lhs: Args[0], Rhs: Args[1], KeyLoc: RParenLoc); |
1316 | |
1317 | switch (Kind) { |
1318 | case clang::BTT_ReferenceBindsToTemporary: |
1319 | case clang::BTT_ReferenceConstructsFromTemporary: |
1320 | case clang::BTT_ReferenceConvertsFromTemporary: |
1321 | case clang::TT_IsConstructible: |
1322 | case clang::TT_IsNothrowConstructible: |
1323 | case clang::TT_IsTriviallyConstructible: { |
1324 | // C++11 [meta.unary.prop]: |
1325 | // is_trivially_constructible is defined as: |
1326 | // |
1327 | // is_constructible<T, Args...>::value is true and the variable |
1328 | // definition for is_constructible, as defined below, is known to call |
1329 | // no operation that is not trivial. |
1330 | // |
1331 | // The predicate condition for a template specialization |
1332 | // is_constructible<T, Args...> shall be satisfied if and only if the |
1333 | // following variable definition would be well-formed for some invented |
1334 | // variable t: |
1335 | // |
1336 | // T t(create<Args>()...); |
1337 | assert(!Args.empty()); |
1338 | |
1339 | // Precondition: T and all types in the parameter pack Args shall be |
1340 | // complete types, (possibly cv-qualified) void, or arrays of |
1341 | // unknown bound. |
1342 | for (const auto *TSI : Args) { |
1343 | QualType ArgTy = TSI->getType(); |
1344 | if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) |
1345 | continue; |
1346 | |
1347 | if (S.RequireCompleteType( |
1348 | Loc: KWLoc, T: ArgTy, DiagID: diag::err_incomplete_type_used_in_type_trait_expr)) |
1349 | return false; |
1350 | } |
1351 | |
1352 | // Make sure the first argument is not incomplete nor a function type. |
1353 | QualType T = Args[0]->getType(); |
1354 | if (T->isIncompleteType() || T->isFunctionType()) |
1355 | return false; |
1356 | |
1357 | // Make sure the first argument is not an abstract type. |
1358 | CXXRecordDecl *RD = T->getAsCXXRecordDecl(); |
1359 | if (RD && RD->isAbstract()) |
1360 | return false; |
1361 | |
1362 | // LWG3819: For reference_meows_from_temporary traits, && is not added to |
1363 | // the source object type. |
1364 | // Otherwise, compute the result of add_rvalue_reference_t. |
1365 | bool UseRawObjectType = |
1366 | Kind == clang::BTT_ReferenceBindsToTemporary || |
1367 | Kind == clang::BTT_ReferenceConstructsFromTemporary || |
1368 | Kind == clang::BTT_ReferenceConvertsFromTemporary; |
1369 | |
1370 | llvm::BumpPtrAllocator OpaqueExprAllocator; |
1371 | SmallVector<Expr *, 2> ArgExprs; |
1372 | ArgExprs.reserve(N: Args.size() - 1); |
1373 | for (unsigned I = 1, N = Args.size(); I != N; ++I) { |
1374 | QualType ArgTy = Args[I]->getType(); |
1375 | if ((ArgTy->isObjectType() && !UseRawObjectType) || |
1376 | ArgTy->isFunctionType()) |
1377 | ArgTy = S.Context.getRValueReferenceType(T: ArgTy); |
1378 | ArgExprs.push_back( |
1379 | Elt: new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) |
1380 | OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(), |
1381 | ArgTy.getNonLValueExprType(Context: S.Context), |
1382 | Expr::getValueKindForType(T: ArgTy))); |
1383 | } |
1384 | |
1385 | // Perform the initialization in an unevaluated context within a SFINAE |
1386 | // trap at translation unit scope. |
1387 | EnterExpressionEvaluationContext Unevaluated( |
1388 | S, Sema::ExpressionEvaluationContext::Unevaluated); |
1389 | Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); |
1390 | Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); |
1391 | InitializedEntity To( |
1392 | InitializedEntity::InitializeTemporary(Context&: S.Context, TypeInfo: Args[0])); |
1393 | InitializationKind InitKind( |
1394 | Kind == clang::BTT_ReferenceConvertsFromTemporary |
1395 | ? InitializationKind::CreateCopy(InitLoc: KWLoc, EqualLoc: KWLoc) |
1396 | : InitializationKind::CreateDirect(InitLoc: KWLoc, LParenLoc: KWLoc, RParenLoc)); |
1397 | InitializationSequence Init(S, To, InitKind, ArgExprs); |
1398 | if (Init.Failed()) |
1399 | return false; |
1400 | |
1401 | ExprResult Result = Init.Perform(S, Entity: To, Kind: InitKind, Args: ArgExprs); |
1402 | if (Result.isInvalid() || SFINAE.hasErrorOccurred()) |
1403 | return false; |
1404 | |
1405 | if (Kind == clang::TT_IsConstructible) |
1406 | return true; |
1407 | |
1408 | if (Kind == clang::BTT_ReferenceBindsToTemporary || |
1409 | Kind == clang::BTT_ReferenceConstructsFromTemporary || |
1410 | Kind == clang::BTT_ReferenceConvertsFromTemporary) { |
1411 | if (!T->isReferenceType()) |
1412 | return false; |
1413 | |
1414 | // A function reference never binds to a temporary object. |
1415 | if (T.getNonReferenceType()->isFunctionType()) |
1416 | return false; |
1417 | |
1418 | if (!Init.isDirectReferenceBinding()) |
1419 | return true; |
1420 | |
1421 | if (Kind == clang::BTT_ReferenceBindsToTemporary) |
1422 | return false; |
1423 | |
1424 | QualType U = Args[1]->getType(); |
1425 | if (U->isReferenceType()) |
1426 | return false; |
1427 | |
1428 | TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo( |
1429 | T: S.Context.getPointerType(T: T.getNonReferenceType())); |
1430 | TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo( |
1431 | T: S.Context.getPointerType(T: U.getNonReferenceType())); |
1432 | return !CheckConvertibilityForTypeTraits(Self&: S, Lhs: UPtr, Rhs: TPtr, KeyLoc: RParenLoc, |
1433 | OpaqueExprAllocator) |
1434 | .isInvalid(); |
1435 | } |
1436 | |
1437 | if (Kind == clang::TT_IsNothrowConstructible) |
1438 | return S.canThrow(E: Result.get()) == CT_Cannot; |
1439 | |
1440 | if (Kind == clang::TT_IsTriviallyConstructible) { |
1441 | // Under Objective-C ARC and Weak, if the destination has non-trivial |
1442 | // Objective-C lifetime, this is a non-trivial construction. |
1443 | if (T.getNonReferenceType().hasNonTrivialObjCLifetime()) |
1444 | return false; |
1445 | |
1446 | // The initialization succeeded; now make sure there are no non-trivial |
1447 | // calls. |
1448 | return !Result.get()->hasNonTrivialCall(Ctx: S.Context); |
1449 | } |
1450 | |
1451 | llvm_unreachable("unhandled type trait" ); |
1452 | return false; |
1453 | } |
1454 | default: |
1455 | llvm_unreachable("not a TT" ); |
1456 | } |
1457 | |
1458 | return false; |
1459 | } |
1460 | |
1461 | namespace { |
1462 | void DiagnoseBuiltinDeprecation(Sema &S, TypeTrait Kind, SourceLocation KWLoc) { |
1463 | TypeTrait Replacement; |
1464 | switch (Kind) { |
1465 | case UTT_HasNothrowAssign: |
1466 | case UTT_HasNothrowMoveAssign: |
1467 | Replacement = BTT_IsNothrowAssignable; |
1468 | break; |
1469 | case UTT_HasNothrowCopy: |
1470 | case UTT_HasNothrowConstructor: |
1471 | Replacement = TT_IsNothrowConstructible; |
1472 | break; |
1473 | case UTT_HasTrivialAssign: |
1474 | case UTT_HasTrivialMoveAssign: |
1475 | Replacement = BTT_IsTriviallyAssignable; |
1476 | break; |
1477 | case UTT_HasTrivialCopy: |
1478 | Replacement = UTT_IsTriviallyCopyable; |
1479 | break; |
1480 | case UTT_HasTrivialDefaultConstructor: |
1481 | case UTT_HasTrivialMoveConstructor: |
1482 | Replacement = TT_IsTriviallyConstructible; |
1483 | break; |
1484 | case UTT_HasTrivialDestructor: |
1485 | Replacement = UTT_IsTriviallyDestructible; |
1486 | break; |
1487 | case UTT_IsTriviallyRelocatable: |
1488 | Replacement = clang::UTT_IsCppTriviallyRelocatable; |
1489 | break; |
1490 | case BTT_ReferenceBindsToTemporary: |
1491 | Replacement = clang::BTT_ReferenceConstructsFromTemporary; |
1492 | break; |
1493 | default: |
1494 | return; |
1495 | } |
1496 | S.Diag(Loc: KWLoc, DiagID: diag::warn_deprecated_builtin) |
1497 | << getTraitSpelling(T: Kind) << getTraitSpelling(T: Replacement); |
1498 | } |
1499 | } // namespace |
1500 | |
1501 | bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) { |
1502 | if (Arity && N != Arity) { |
1503 | Diag(Loc, DiagID: diag::err_type_trait_arity) |
1504 | << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc); |
1505 | return false; |
1506 | } |
1507 | |
1508 | if (!Arity && N == 0) { |
1509 | Diag(Loc, DiagID: diag::err_type_trait_arity) |
1510 | << 1 << 1 << 1 << (int)N << SourceRange(Loc); |
1511 | return false; |
1512 | } |
1513 | return true; |
1514 | } |
1515 | |
1516 | enum class TypeTraitReturnType { |
1517 | Bool, |
1518 | SizeT, |
1519 | }; |
1520 | |
1521 | static TypeTraitReturnType GetReturnType(TypeTrait Kind) { |
1522 | if (Kind == TypeTrait::UTT_StructuredBindingSize) |
1523 | return TypeTraitReturnType::SizeT; |
1524 | return TypeTraitReturnType::Bool; |
1525 | } |
1526 | |
1527 | ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, |
1528 | ArrayRef<TypeSourceInfo *> Args, |
1529 | SourceLocation RParenLoc) { |
1530 | if (!CheckTypeTraitArity(Arity: getTypeTraitArity(T: Kind), Loc: KWLoc, N: Args.size())) |
1531 | return ExprError(); |
1532 | |
1533 | if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness( |
1534 | S&: *this, UTT: Kind, Loc: KWLoc, ArgTy: Args[0]->getType())) |
1535 | return ExprError(); |
1536 | |
1537 | DiagnoseBuiltinDeprecation(S&: *this, Kind, KWLoc); |
1538 | |
1539 | bool Dependent = false; |
1540 | for (unsigned I = 0, N = Args.size(); I != N; ++I) { |
1541 | if (Args[I]->getType()->isDependentType()) { |
1542 | Dependent = true; |
1543 | break; |
1544 | } |
1545 | } |
1546 | |
1547 | switch (GetReturnType(Kind)) { |
1548 | case TypeTraitReturnType::Bool: { |
1549 | bool Result = EvaluateBooleanTypeTrait(S&: *this, Kind, KWLoc, Args, RParenLoc, |
1550 | IsDependent: Dependent); |
1551 | return TypeTraitExpr::Create(C: Context, T: Context.getLogicalOperationType(), |
1552 | Loc: KWLoc, Kind, Args, RParenLoc, Value: Result); |
1553 | } |
1554 | case TypeTraitReturnType::SizeT: { |
1555 | APValue Result = |
1556 | EvaluateSizeTTypeTrait(S&: *this, Kind, KWLoc, Args, RParenLoc, IsDependent: Dependent); |
1557 | return TypeTraitExpr::Create(C: Context, T: Context.getSizeType(), Loc: KWLoc, Kind, |
1558 | Args, RParenLoc, Value: Result); |
1559 | } |
1560 | } |
1561 | llvm_unreachable("unhandled type trait return type" ); |
1562 | } |
1563 | |
1564 | ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, |
1565 | ArrayRef<ParsedType> Args, |
1566 | SourceLocation RParenLoc) { |
1567 | SmallVector<TypeSourceInfo *, 4> ConvertedArgs; |
1568 | ConvertedArgs.reserve(N: Args.size()); |
1569 | |
1570 | for (unsigned I = 0, N = Args.size(); I != N; ++I) { |
1571 | TypeSourceInfo *TInfo; |
1572 | QualType T = GetTypeFromParser(Ty: Args[I], TInfo: &TInfo); |
1573 | if (!TInfo) |
1574 | TInfo = Context.getTrivialTypeSourceInfo(T, Loc: KWLoc); |
1575 | |
1576 | ConvertedArgs.push_back(Elt: TInfo); |
1577 | } |
1578 | |
1579 | return BuildTypeTrait(Kind, KWLoc, Args: ConvertedArgs, RParenLoc); |
1580 | } |
1581 | |
1582 | bool Sema::BuiltinIsBaseOf(SourceLocation RhsTLoc, QualType LhsT, |
1583 | QualType RhsT) { |
1584 | // C++0x [meta.rel]p2 |
1585 | // Base is a base class of Derived without regard to cv-qualifiers or |
1586 | // Base and Derived are not unions and name the same class type without |
1587 | // regard to cv-qualifiers. |
1588 | |
1589 | const RecordType *lhsRecord = LhsT->getAs<RecordType>(); |
1590 | const RecordType *rhsRecord = RhsT->getAs<RecordType>(); |
1591 | if (!rhsRecord || !lhsRecord) { |
1592 | const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>(); |
1593 | const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>(); |
1594 | if (!LHSObjTy || !RHSObjTy) |
1595 | return false; |
1596 | |
1597 | ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface(); |
1598 | ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface(); |
1599 | if (!BaseInterface || !DerivedInterface) |
1600 | return false; |
1601 | |
1602 | if (RequireCompleteType(Loc: RhsTLoc, T: RhsT, |
1603 | DiagID: diag::err_incomplete_type_used_in_type_trait_expr)) |
1604 | return false; |
1605 | |
1606 | return BaseInterface->isSuperClassOf(I: DerivedInterface); |
1607 | } |
1608 | |
1609 | assert(Context.hasSameUnqualifiedType(LhsT, RhsT) == |
1610 | (lhsRecord == rhsRecord)); |
1611 | |
1612 | // Unions are never base classes, and never have base classes. |
1613 | // It doesn't matter if they are complete or not. See PR#41843 |
1614 | if (lhsRecord && lhsRecord->getDecl()->isUnion()) |
1615 | return false; |
1616 | if (rhsRecord && rhsRecord->getDecl()->isUnion()) |
1617 | return false; |
1618 | |
1619 | if (lhsRecord == rhsRecord) |
1620 | return true; |
1621 | |
1622 | // C++0x [meta.rel]p2: |
1623 | // If Base and Derived are class types and are different types |
1624 | // (ignoring possible cv-qualifiers) then Derived shall be a |
1625 | // complete type. |
1626 | if (RequireCompleteType(Loc: RhsTLoc, T: RhsT, |
1627 | DiagID: diag::err_incomplete_type_used_in_type_trait_expr)) |
1628 | return false; |
1629 | |
1630 | return cast<CXXRecordDecl>(Val: rhsRecord->getDecl()) |
1631 | ->isDerivedFrom(Base: cast<CXXRecordDecl>(Val: lhsRecord->getDecl())); |
1632 | } |
1633 | |
1634 | static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, |
1635 | const TypeSourceInfo *Lhs, |
1636 | const TypeSourceInfo *Rhs, |
1637 | SourceLocation KeyLoc) { |
1638 | QualType LhsT = Lhs->getType(); |
1639 | QualType RhsT = Rhs->getType(); |
1640 | |
1641 | assert(!LhsT->isDependentType() && !RhsT->isDependentType() && |
1642 | "Cannot evaluate traits of dependent types" ); |
1643 | |
1644 | switch (BTT) { |
1645 | case BTT_IsBaseOf: |
1646 | return Self.BuiltinIsBaseOf(RhsTLoc: Rhs->getTypeLoc().getBeginLoc(), LhsT, RhsT); |
1647 | |
1648 | case BTT_IsVirtualBaseOf: { |
1649 | const RecordType *BaseRecord = LhsT->getAs<RecordType>(); |
1650 | const RecordType *DerivedRecord = RhsT->getAs<RecordType>(); |
1651 | |
1652 | if (!BaseRecord || !DerivedRecord) { |
1653 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: Lhs, |
1654 | TypeTraitID: tok::kw___builtin_is_virtual_base_of); |
1655 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: Rhs, |
1656 | TypeTraitID: tok::kw___builtin_is_virtual_base_of); |
1657 | return false; |
1658 | } |
1659 | |
1660 | if (BaseRecord->isUnionType() || DerivedRecord->isUnionType()) |
1661 | return false; |
1662 | |
1663 | if (!BaseRecord->isStructureOrClassType() || |
1664 | !DerivedRecord->isStructureOrClassType()) |
1665 | return false; |
1666 | |
1667 | if (Self.RequireCompleteType(Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT, |
1668 | DiagID: diag::err_incomplete_type)) |
1669 | return false; |
1670 | |
1671 | return cast<CXXRecordDecl>(Val: DerivedRecord->getDecl()) |
1672 | ->isVirtuallyDerivedFrom(Base: cast<CXXRecordDecl>(Val: BaseRecord->getDecl())); |
1673 | } |
1674 | case BTT_IsSame: |
1675 | return Self.Context.hasSameType(T1: LhsT, T2: RhsT); |
1676 | case BTT_TypeCompatible: { |
1677 | // GCC ignores cv-qualifiers on arrays for this builtin. |
1678 | Qualifiers LhsQuals, RhsQuals; |
1679 | QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(T: LhsT, Quals&: LhsQuals); |
1680 | QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(T: RhsT, Quals&: RhsQuals); |
1681 | return Self.Context.typesAreCompatible(T1: Lhs, T2: Rhs); |
1682 | } |
1683 | case BTT_IsConvertible: |
1684 | case BTT_IsConvertibleTo: |
1685 | case BTT_IsNothrowConvertible: { |
1686 | if (RhsT->isVoidType()) |
1687 | return LhsT->isVoidType(); |
1688 | llvm::BumpPtrAllocator OpaqueExprAllocator; |
1689 | ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc, |
1690 | OpaqueExprAllocator); |
1691 | if (Result.isInvalid()) |
1692 | return false; |
1693 | |
1694 | if (BTT != BTT_IsNothrowConvertible) |
1695 | return true; |
1696 | |
1697 | return Self.canThrow(E: Result.get()) == CT_Cannot; |
1698 | } |
1699 | |
1700 | case BTT_IsAssignable: |
1701 | case BTT_IsNothrowAssignable: |
1702 | case BTT_IsTriviallyAssignable: { |
1703 | // C++11 [meta.unary.prop]p3: |
1704 | // is_trivially_assignable is defined as: |
1705 | // is_assignable<T, U>::value is true and the assignment, as defined by |
1706 | // is_assignable, is known to call no operation that is not trivial |
1707 | // |
1708 | // is_assignable is defined as: |
1709 | // The expression declval<T>() = declval<U>() is well-formed when |
1710 | // treated as an unevaluated operand (Clause 5). |
1711 | // |
1712 | // For both, T and U shall be complete types, (possibly cv-qualified) |
1713 | // void, or arrays of unknown bound. |
1714 | if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && |
1715 | Self.RequireCompleteType( |
1716 | Loc: Lhs->getTypeLoc().getBeginLoc(), T: LhsT, |
1717 | DiagID: diag::err_incomplete_type_used_in_type_trait_expr)) |
1718 | return false; |
1719 | if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && |
1720 | Self.RequireCompleteType( |
1721 | Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT, |
1722 | DiagID: diag::err_incomplete_type_used_in_type_trait_expr)) |
1723 | return false; |
1724 | |
1725 | // cv void is never assignable. |
1726 | if (LhsT->isVoidType() || RhsT->isVoidType()) |
1727 | return false; |
1728 | |
1729 | // Build expressions that emulate the effect of declval<T>() and |
1730 | // declval<U>(). |
1731 | auto createDeclValExpr = [&](QualType Ty) -> OpaqueValueExpr { |
1732 | if (Ty->isObjectType() || Ty->isFunctionType()) |
1733 | Ty = Self.Context.getRValueReferenceType(T: Ty); |
1734 | return {KeyLoc, Ty.getNonLValueExprType(Context: Self.Context), |
1735 | Expr::getValueKindForType(T: Ty)}; |
1736 | }; |
1737 | |
1738 | auto Lhs = createDeclValExpr(LhsT); |
1739 | auto Rhs = createDeclValExpr(RhsT); |
1740 | |
1741 | // Attempt the assignment in an unevaluated context within a SFINAE |
1742 | // trap at translation unit scope. |
1743 | EnterExpressionEvaluationContext Unevaluated( |
1744 | Self, Sema::ExpressionEvaluationContext::Unevaluated); |
1745 | Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true); |
1746 | Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); |
1747 | ExprResult Result = |
1748 | Self.BuildBinOp(/*S=*/nullptr, OpLoc: KeyLoc, Opc: BO_Assign, LHSExpr: &Lhs, RHSExpr: &Rhs); |
1749 | if (Result.isInvalid()) |
1750 | return false; |
1751 | |
1752 | // Treat the assignment as unused for the purpose of -Wdeprecated-volatile. |
1753 | Self.CheckUnusedVolatileAssignment(E: Result.get()); |
1754 | |
1755 | if (SFINAE.hasErrorOccurred()) |
1756 | return false; |
1757 | |
1758 | if (BTT == BTT_IsAssignable) |
1759 | return true; |
1760 | |
1761 | if (BTT == BTT_IsNothrowAssignable) |
1762 | return Self.canThrow(E: Result.get()) == CT_Cannot; |
1763 | |
1764 | if (BTT == BTT_IsTriviallyAssignable) { |
1765 | // Under Objective-C ARC and Weak, if the destination has non-trivial |
1766 | // Objective-C lifetime, this is a non-trivial assignment. |
1767 | if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime()) |
1768 | return false; |
1769 | |
1770 | return !Result.get()->hasNonTrivialCall(Ctx: Self.Context); |
1771 | } |
1772 | |
1773 | llvm_unreachable("unhandled type trait" ); |
1774 | return false; |
1775 | } |
1776 | case BTT_IsLayoutCompatible: { |
1777 | if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType()) |
1778 | Self.RequireCompleteType(Loc: Lhs->getTypeLoc().getBeginLoc(), T: LhsT, |
1779 | DiagID: diag::err_incomplete_type); |
1780 | if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType()) |
1781 | Self.RequireCompleteType(Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT, |
1782 | DiagID: diag::err_incomplete_type); |
1783 | |
1784 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: Lhs, TypeTraitID: tok::kw___is_layout_compatible); |
1785 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: Rhs, TypeTraitID: tok::kw___is_layout_compatible); |
1786 | |
1787 | return Self.IsLayoutCompatible(T1: LhsT, T2: RhsT); |
1788 | } |
1789 | case BTT_IsPointerInterconvertibleBaseOf: { |
1790 | if (LhsT->isStructureOrClassType() && RhsT->isStructureOrClassType() && |
1791 | !Self.getASTContext().hasSameUnqualifiedType(T1: LhsT, T2: RhsT)) { |
1792 | Self.RequireCompleteType(Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT, |
1793 | DiagID: diag::err_incomplete_type); |
1794 | } |
1795 | |
1796 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: Lhs, |
1797 | TypeTraitID: tok::kw___is_pointer_interconvertible_base_of); |
1798 | DiagnoseVLAInCXXTypeTrait(S&: Self, T: Rhs, |
1799 | TypeTraitID: tok::kw___is_pointer_interconvertible_base_of); |
1800 | |
1801 | return Self.IsPointerInterconvertibleBaseOf(Base: Lhs, Derived: Rhs); |
1802 | } |
1803 | case BTT_IsDeducible: { |
1804 | const auto *TSTToBeDeduced = cast<DeducedTemplateSpecializationType>(Val&: LhsT); |
1805 | sema::TemplateDeductionInfo Info(KeyLoc); |
1806 | return Self.DeduceTemplateArgumentsFromType( |
1807 | TD: TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), FromType: RhsT, |
1808 | Info) == TemplateDeductionResult::Success; |
1809 | } |
1810 | case BTT_IsScalarizedLayoutCompatible: { |
1811 | if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && |
1812 | Self.RequireCompleteType(Loc: Lhs->getTypeLoc().getBeginLoc(), T: LhsT, |
1813 | DiagID: diag::err_incomplete_type)) |
1814 | return true; |
1815 | if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && |
1816 | Self.RequireCompleteType(Loc: Rhs->getTypeLoc().getBeginLoc(), T: RhsT, |
1817 | DiagID: diag::err_incomplete_type)) |
1818 | return true; |
1819 | |
1820 | DiagnoseVLAInCXXTypeTrait( |
1821 | S&: Self, T: Lhs, TypeTraitID: tok::kw___builtin_hlsl_is_scalarized_layout_compatible); |
1822 | DiagnoseVLAInCXXTypeTrait( |
1823 | S&: Self, T: Rhs, TypeTraitID: tok::kw___builtin_hlsl_is_scalarized_layout_compatible); |
1824 | |
1825 | return Self.HLSL().IsScalarizedLayoutCompatible(T1: LhsT, T2: RhsT); |
1826 | } |
1827 | default: |
1828 | llvm_unreachable("not a BTT" ); |
1829 | } |
1830 | llvm_unreachable("Unknown type trait or not implemented" ); |
1831 | } |
1832 | |
1833 | ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, |
1834 | ParsedType Ty, Expr *DimExpr, |
1835 | SourceLocation RParen) { |
1836 | TypeSourceInfo *TSInfo; |
1837 | QualType T = GetTypeFromParser(Ty, TInfo: &TSInfo); |
1838 | if (!TSInfo) |
1839 | TSInfo = Context.getTrivialTypeSourceInfo(T); |
1840 | |
1841 | return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen); |
1842 | } |
1843 | |
1844 | static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT, |
1845 | QualType T, Expr *DimExpr, |
1846 | SourceLocation KeyLoc) { |
1847 | assert(!T->isDependentType() && "Cannot evaluate traits of dependent type" ); |
1848 | |
1849 | switch (ATT) { |
1850 | case ATT_ArrayRank: |
1851 | if (T->isArrayType()) { |
1852 | unsigned Dim = 0; |
1853 | while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { |
1854 | ++Dim; |
1855 | T = AT->getElementType(); |
1856 | } |
1857 | return Dim; |
1858 | } |
1859 | return 0; |
1860 | |
1861 | case ATT_ArrayExtent: { |
1862 | llvm::APSInt Value; |
1863 | uint64_t Dim; |
1864 | if (Self.VerifyIntegerConstantExpression( |
1865 | E: DimExpr, Result: &Value, DiagID: diag::err_dimension_expr_not_constant_integer) |
1866 | .isInvalid()) |
1867 | return 0; |
1868 | if (Value.isSigned() && Value.isNegative()) { |
1869 | Self.Diag(Loc: KeyLoc, DiagID: diag::err_dimension_expr_not_constant_integer) |
1870 | << DimExpr->getSourceRange(); |
1871 | return 0; |
1872 | } |
1873 | Dim = Value.getLimitedValue(); |
1874 | |
1875 | if (T->isArrayType()) { |
1876 | unsigned D = 0; |
1877 | bool Matched = false; |
1878 | while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { |
1879 | if (Dim == D) { |
1880 | Matched = true; |
1881 | break; |
1882 | } |
1883 | ++D; |
1884 | T = AT->getElementType(); |
1885 | } |
1886 | |
1887 | if (Matched && T->isArrayType()) { |
1888 | if (const ConstantArrayType *CAT = |
1889 | Self.Context.getAsConstantArrayType(T)) |
1890 | return CAT->getLimitedSize(); |
1891 | } |
1892 | } |
1893 | return 0; |
1894 | } |
1895 | } |
1896 | llvm_unreachable("Unknown type trait or not implemented" ); |
1897 | } |
1898 | |
1899 | ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, |
1900 | TypeSourceInfo *TSInfo, Expr *DimExpr, |
1901 | SourceLocation RParen) { |
1902 | QualType T = TSInfo->getType(); |
1903 | |
1904 | // FIXME: This should likely be tracked as an APInt to remove any host |
1905 | // assumptions about the width of size_t on the target. |
1906 | uint64_t Value = 0; |
1907 | if (!T->isDependentType()) |
1908 | Value = EvaluateArrayTypeTrait(Self&: *this, ATT, T, DimExpr, KeyLoc: KWLoc); |
1909 | |
1910 | // While the specification for these traits from the Embarcadero C++ |
1911 | // compiler's documentation says the return type is 'unsigned int', Clang |
1912 | // returns 'size_t'. On Windows, the primary platform for the Embarcadero |
1913 | // compiler, there is no difference. On several other platforms this is an |
1914 | // important distinction. |
1915 | return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr, |
1916 | RParen, Context.getSizeType()); |
1917 | } |
1918 | |
1919 | ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, |
1920 | Expr *Queried, SourceLocation RParen) { |
1921 | // If error parsing the expression, ignore. |
1922 | if (!Queried) |
1923 | return ExprError(); |
1924 | |
1925 | ExprResult Result = BuildExpressionTrait(OET: ET, KWLoc, Queried, RParen); |
1926 | |
1927 | return Result; |
1928 | } |
1929 | |
1930 | static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) { |
1931 | switch (ET) { |
1932 | case ET_IsLValueExpr: |
1933 | return E->isLValue(); |
1934 | case ET_IsRValueExpr: |
1935 | return E->isPRValue(); |
1936 | } |
1937 | llvm_unreachable("Expression trait not covered by switch" ); |
1938 | } |
1939 | |
1940 | ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, |
1941 | Expr *Queried, SourceLocation RParen) { |
1942 | if (Queried->isTypeDependent()) { |
1943 | // Delay type-checking for type-dependent expressions. |
1944 | } else if (Queried->hasPlaceholderType()) { |
1945 | ExprResult PE = CheckPlaceholderExpr(E: Queried); |
1946 | if (PE.isInvalid()) |
1947 | return ExprError(); |
1948 | return BuildExpressionTrait(ET, KWLoc, Queried: PE.get(), RParen); |
1949 | } |
1950 | |
1951 | bool Value = EvaluateExpressionTrait(ET, E: Queried); |
1952 | |
1953 | return new (Context) |
1954 | ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy); |
1955 | } |
1956 | |
1957 | static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) { |
1958 | return llvm::StringSwitch<std::optional<TypeTrait>>(Name) |
1959 | .Case(S: "is_trivially_relocatable" , |
1960 | Value: TypeTrait::UTT_IsCppTriviallyRelocatable) |
1961 | .Case(S: "is_replaceable" , Value: TypeTrait::UTT_IsReplaceable) |
1962 | .Case(S: "is_trivially_copyable" , Value: TypeTrait::UTT_IsTriviallyCopyable) |
1963 | .Case(S: "is_assignable" , Value: TypeTrait::BTT_IsAssignable) |
1964 | .Case(S: "is_empty" , Value: TypeTrait::UTT_IsEmpty) |
1965 | .Case(S: "is_standard_layout" , Value: TypeTrait::UTT_IsStandardLayout) |
1966 | .Default(Value: std::nullopt); |
1967 | } |
1968 | |
1969 | using = |
1970 | std::optional<std::pair<TypeTrait, llvm::SmallVector<QualType, 1>>>; |
1971 | |
1972 | // Recognize type traits that are builting type traits, or known standard |
1973 | // type traits in <type_traits>. Note that at this point we assume the |
1974 | // trait evaluated to false, so we need only to recognize the shape of the |
1975 | // outer-most symbol. |
1976 | static ExtractedTypeTraitInfo (const Expr *E) { |
1977 | llvm::SmallVector<QualType, 1> Args; |
1978 | std::optional<TypeTrait> Trait; |
1979 | |
1980 | // builtins |
1981 | if (const auto *TraitExpr = dyn_cast<TypeTraitExpr>(Val: E)) { |
1982 | Trait = TraitExpr->getTrait(); |
1983 | for (const auto *Arg : TraitExpr->getArgs()) |
1984 | Args.push_back(Elt: Arg->getType()); |
1985 | return {{Trait.value(), std::move(Args)}}; |
1986 | } |
1987 | const auto *Ref = dyn_cast<DeclRefExpr>(Val: E); |
1988 | if (!Ref) |
1989 | return std::nullopt; |
1990 | |
1991 | // std::is_xxx_v<> |
1992 | if (const auto *VD = |
1993 | dyn_cast<VarTemplateSpecializationDecl>(Val: Ref->getDecl())) { |
1994 | if (!VD->isInStdNamespace()) |
1995 | return std::nullopt; |
1996 | StringRef Name = VD->getIdentifier()->getName(); |
1997 | if (!Name.consume_back(Suffix: "_v" )) |
1998 | return std::nullopt; |
1999 | Trait = StdNameToTypeTrait(Name); |
2000 | if (!Trait) |
2001 | return std::nullopt; |
2002 | for (const auto &Arg : VD->getTemplateArgs().asArray()) |
2003 | Args.push_back(Elt: Arg.getAsType()); |
2004 | return {{Trait.value(), std::move(Args)}}; |
2005 | } |
2006 | |
2007 | // std::is_xxx<>::value |
2008 | if (const auto *VD = dyn_cast<VarDecl>(Val: Ref->getDecl()); |
2009 | Ref->hasQualifier() && VD && VD->getIdentifier()->isStr(Str: "value" )) { |
2010 | const Type *T = Ref->getQualifier()->getAsType(); |
2011 | if (!T) |
2012 | return std::nullopt; |
2013 | const TemplateSpecializationType *Ts = |
2014 | T->getAs<TemplateSpecializationType>(); |
2015 | if (!Ts) |
2016 | return std::nullopt; |
2017 | const TemplateDecl *D = Ts->getTemplateName().getAsTemplateDecl(); |
2018 | if (!D || !D->isInStdNamespace()) |
2019 | return std::nullopt; |
2020 | Trait = StdNameToTypeTrait(Name: D->getIdentifier()->getName()); |
2021 | if (!Trait) |
2022 | return std::nullopt; |
2023 | for (const auto &Arg : Ts->template_arguments()) |
2024 | Args.push_back(Elt: Arg.getAsType()); |
2025 | return {{Trait.value(), std::move(Args)}}; |
2026 | } |
2027 | return std::nullopt; |
2028 | } |
2029 | |
2030 | static void DiagnoseNonDefaultMovable(Sema &SemaRef, SourceLocation Loc, |
2031 | const CXXRecordDecl *D) { |
2032 | if (D->isUnion()) { |
2033 | auto DiagSPM = [&](CXXSpecialMemberKind K, bool Has) { |
2034 | if (Has) |
2035 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2036 | << diag::TraitNotSatisfiedReason::UnionWithUserDeclaredSMF << K; |
2037 | }; |
2038 | DiagSPM(CXXSpecialMemberKind::CopyConstructor, |
2039 | D->hasUserDeclaredCopyConstructor()); |
2040 | DiagSPM(CXXSpecialMemberKind::CopyAssignment, |
2041 | D->hasUserDeclaredCopyAssignment()); |
2042 | DiagSPM(CXXSpecialMemberKind::MoveConstructor, |
2043 | D->hasUserDeclaredMoveConstructor()); |
2044 | DiagSPM(CXXSpecialMemberKind::MoveAssignment, |
2045 | D->hasUserDeclaredMoveAssignment()); |
2046 | return; |
2047 | } |
2048 | |
2049 | if (!D->hasSimpleMoveConstructor() && !D->hasSimpleCopyConstructor()) { |
2050 | const auto *Decl = cast_or_null<CXXConstructorDecl>( |
2051 | Val: LookupSpecialMemberFromXValue(SemaRef, RD: D, /*Assign=*/false)); |
2052 | if (Decl && Decl->isUserProvided()) |
2053 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2054 | << diag::TraitNotSatisfiedReason::UserProvidedCtr |
2055 | << Decl->isMoveConstructor() << Decl->getSourceRange(); |
2056 | } |
2057 | if (!D->hasSimpleMoveAssignment() && !D->hasSimpleCopyAssignment()) { |
2058 | CXXMethodDecl *Decl = |
2059 | LookupSpecialMemberFromXValue(SemaRef, RD: D, /*Assign=*/true); |
2060 | if (Decl && Decl->isUserProvided()) |
2061 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2062 | << diag::TraitNotSatisfiedReason::UserProvidedAssign |
2063 | << Decl->isMoveAssignmentOperator() << Decl->getSourceRange(); |
2064 | } |
2065 | if (CXXDestructorDecl *Dtr = D->getDestructor()) { |
2066 | Dtr = Dtr->getCanonicalDecl(); |
2067 | if (Dtr->isUserProvided() && !Dtr->isDefaulted()) |
2068 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2069 | << diag::TraitNotSatisfiedReason::DeletedDtr << /*User Provided*/ 1 |
2070 | << Dtr->getSourceRange(); |
2071 | } |
2072 | } |
2073 | |
2074 | static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef, |
2075 | SourceLocation Loc, |
2076 | const CXXRecordDecl *D) { |
2077 | for (const CXXBaseSpecifier &B : D->bases()) { |
2078 | assert(B.getType()->getAsCXXRecordDecl() && "invalid base?" ); |
2079 | if (B.isVirtual()) |
2080 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2081 | << diag::TraitNotSatisfiedReason::VBase << B.getType() |
2082 | << B.getSourceRange(); |
2083 | if (!SemaRef.IsCXXTriviallyRelocatableType(Type: B.getType())) |
2084 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2085 | << diag::TraitNotSatisfiedReason::NTRBase << B.getType() |
2086 | << B.getSourceRange(); |
2087 | } |
2088 | for (const FieldDecl *Field : D->fields()) { |
2089 | if (!Field->getType()->isReferenceType() && |
2090 | !SemaRef.IsCXXTriviallyRelocatableType(Type: Field->getType())) |
2091 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2092 | << diag::TraitNotSatisfiedReason::NTRField << Field |
2093 | << Field->getType() << Field->getSourceRange(); |
2094 | } |
2095 | if (D->hasDeletedDestructor()) |
2096 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2097 | << diag::TraitNotSatisfiedReason::DeletedDtr << /*Deleted*/ 0 |
2098 | << D->getDestructor()->getSourceRange(); |
2099 | |
2100 | if (D->hasAttr<TriviallyRelocatableAttr>()) |
2101 | return; |
2102 | DiagnoseNonDefaultMovable(SemaRef, Loc, D); |
2103 | } |
2104 | |
2105 | static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef, |
2106 | SourceLocation Loc, |
2107 | QualType T) { |
2108 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait) |
2109 | << T << diag::TraitName::TriviallyRelocatable; |
2110 | if (T->isVariablyModifiedType()) |
2111 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2112 | << diag::TraitNotSatisfiedReason::VLA; |
2113 | |
2114 | if (T->isReferenceType()) |
2115 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2116 | << diag::TraitNotSatisfiedReason::Ref; |
2117 | T = T.getNonReferenceType(); |
2118 | |
2119 | if (T.hasNonTrivialObjCLifetime()) |
2120 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2121 | << diag::TraitNotSatisfiedReason::HasArcLifetime; |
2122 | |
2123 | const CXXRecordDecl *D = T->getAsCXXRecordDecl(); |
2124 | if (!D || D->isInvalidDecl()) |
2125 | return; |
2126 | |
2127 | if (D->hasDefinition()) |
2128 | DiagnoseNonTriviallyRelocatableReason(SemaRef, Loc, D); |
2129 | |
2130 | SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2131 | } |
2132 | |
2133 | static void DiagnoseNonReplaceableReason(Sema &SemaRef, SourceLocation Loc, |
2134 | const CXXRecordDecl *D) { |
2135 | for (const CXXBaseSpecifier &B : D->bases()) { |
2136 | assert(B.getType()->getAsCXXRecordDecl() && "invalid base?" ); |
2137 | if (!SemaRef.IsCXXReplaceableType(Type: B.getType())) |
2138 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2139 | << diag::TraitNotSatisfiedReason::NonReplaceableBase << B.getType() |
2140 | << B.getSourceRange(); |
2141 | } |
2142 | for (const FieldDecl *Field : D->fields()) { |
2143 | if (!SemaRef.IsCXXReplaceableType(Type: Field->getType())) |
2144 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2145 | << diag::TraitNotSatisfiedReason::NonReplaceableField << Field |
2146 | << Field->getType() << Field->getSourceRange(); |
2147 | } |
2148 | if (D->hasDeletedDestructor()) |
2149 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2150 | << diag::TraitNotSatisfiedReason::DeletedDtr << /*Deleted*/ 0 |
2151 | << D->getDestructor()->getSourceRange(); |
2152 | |
2153 | if (!D->hasSimpleMoveConstructor() && !D->hasSimpleCopyConstructor()) { |
2154 | const auto *Decl = cast<CXXConstructorDecl>( |
2155 | Val: LookupSpecialMemberFromXValue(SemaRef, RD: D, /*Assign=*/false)); |
2156 | if (Decl && Decl->isDeleted()) |
2157 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2158 | << diag::TraitNotSatisfiedReason::DeletedCtr |
2159 | << Decl->isMoveConstructor() << Decl->getSourceRange(); |
2160 | } |
2161 | if (!D->hasSimpleMoveAssignment() && !D->hasSimpleCopyAssignment()) { |
2162 | CXXMethodDecl *Decl = |
2163 | LookupSpecialMemberFromXValue(SemaRef, RD: D, /*Assign=*/true); |
2164 | if (Decl && Decl->isDeleted()) |
2165 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2166 | << diag::TraitNotSatisfiedReason::DeletedAssign |
2167 | << Decl->isMoveAssignmentOperator() << Decl->getSourceRange(); |
2168 | } |
2169 | |
2170 | if (D->hasAttr<ReplaceableAttr>()) |
2171 | return; |
2172 | DiagnoseNonDefaultMovable(SemaRef, Loc, D); |
2173 | } |
2174 | |
2175 | static void DiagnoseNonReplaceableReason(Sema &SemaRef, SourceLocation Loc, |
2176 | QualType T) { |
2177 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait) |
2178 | << T << diag::TraitName::Replaceable; |
2179 | |
2180 | if (T->isVariablyModifiedType()) |
2181 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2182 | << diag::TraitNotSatisfiedReason::VLA; |
2183 | |
2184 | if (T->isReferenceType()) |
2185 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2186 | << diag::TraitNotSatisfiedReason::Ref; |
2187 | T = T.getNonReferenceType(); |
2188 | |
2189 | if (T.isConstQualified()) |
2190 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2191 | << diag::TraitNotSatisfiedReason::Const; |
2192 | |
2193 | if (T.isVolatileQualified()) |
2194 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2195 | << diag::TraitNotSatisfiedReason::Volatile; |
2196 | |
2197 | bool IsArray = T->isArrayType(); |
2198 | T = SemaRef.getASTContext().getBaseElementType(QT: T.getUnqualifiedType()); |
2199 | |
2200 | if (T->isScalarType()) |
2201 | return; |
2202 | |
2203 | const CXXRecordDecl *D = T->getAsCXXRecordDecl(); |
2204 | if (!D) { |
2205 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2206 | << diag::TraitNotSatisfiedReason::NotScalarOrClass << IsArray; |
2207 | return; |
2208 | } |
2209 | |
2210 | if (D->isInvalidDecl()) |
2211 | return; |
2212 | |
2213 | if (D->hasDefinition()) |
2214 | DiagnoseNonReplaceableReason(SemaRef, Loc, D); |
2215 | |
2216 | SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2217 | } |
2218 | |
2219 | static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, |
2220 | SourceLocation Loc, |
2221 | const CXXRecordDecl *D) { |
2222 | for (const CXXBaseSpecifier &B : D->bases()) { |
2223 | assert(B.getType()->getAsCXXRecordDecl() && "invalid base?" ); |
2224 | if (B.isVirtual()) |
2225 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2226 | << diag::TraitNotSatisfiedReason::VBase << B.getType() |
2227 | << B.getSourceRange(); |
2228 | if (!B.getType().isTriviallyCopyableType(Context: D->getASTContext())) { |
2229 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2230 | << diag::TraitNotSatisfiedReason::NTCBase << B.getType() |
2231 | << B.getSourceRange(); |
2232 | } |
2233 | } |
2234 | for (const FieldDecl *Field : D->fields()) { |
2235 | if (!Field->getType().isTriviallyCopyableType(Context: Field->getASTContext())) |
2236 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2237 | << diag::TraitNotSatisfiedReason::NTCField << Field |
2238 | << Field->getType() << Field->getSourceRange(); |
2239 | } |
2240 | CXXDestructorDecl *Dtr = D->getDestructor(); |
2241 | if (D->hasDeletedDestructor() || (Dtr && !Dtr->isTrivial())) |
2242 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2243 | << diag::TraitNotSatisfiedReason::DeletedDtr |
2244 | << !D->hasDeletedDestructor() << D->getDestructor()->getSourceRange(); |
2245 | |
2246 | for (const CXXMethodDecl *Method : D->methods()) { |
2247 | if (Method->isTrivial() || !Method->isUserProvided()) { |
2248 | continue; |
2249 | } |
2250 | auto SpecialMemberKind = |
2251 | SemaRef.getDefaultedFunctionKind(FD: Method).asSpecialMember(); |
2252 | switch (SpecialMemberKind) { |
2253 | case CXXSpecialMemberKind::CopyConstructor: |
2254 | case CXXSpecialMemberKind::MoveConstructor: |
2255 | case CXXSpecialMemberKind::CopyAssignment: |
2256 | case CXXSpecialMemberKind::MoveAssignment: { |
2257 | bool IsAssignment = |
2258 | SpecialMemberKind == CXXSpecialMemberKind::CopyAssignment || |
2259 | SpecialMemberKind == CXXSpecialMemberKind::MoveAssignment; |
2260 | bool IsMove = |
2261 | SpecialMemberKind == CXXSpecialMemberKind::MoveConstructor || |
2262 | SpecialMemberKind == CXXSpecialMemberKind::MoveAssignment; |
2263 | |
2264 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2265 | << (IsAssignment ? diag::TraitNotSatisfiedReason::UserProvidedAssign |
2266 | : diag::TraitNotSatisfiedReason::UserProvidedCtr) |
2267 | << IsMove << Method->getSourceRange(); |
2268 | break; |
2269 | } |
2270 | default: |
2271 | break; |
2272 | } |
2273 | } |
2274 | } |
2275 | |
2276 | static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, |
2277 | SourceLocation Loc, QualType T) { |
2278 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait) |
2279 | << T << diag::TraitName::TriviallyCopyable; |
2280 | |
2281 | if (T->isReferenceType()) |
2282 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2283 | << diag::TraitNotSatisfiedReason::Ref; |
2284 | |
2285 | const CXXRecordDecl *D = T->getAsCXXRecordDecl(); |
2286 | if (!D || D->isInvalidDecl()) |
2287 | return; |
2288 | |
2289 | if (D->hasDefinition()) |
2290 | DiagnoseNonTriviallyCopyableReason(SemaRef, Loc, D); |
2291 | |
2292 | SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2293 | } |
2294 | |
2295 | static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc, |
2296 | QualType T, QualType U) { |
2297 | const CXXRecordDecl *D = T->getAsCXXRecordDecl(); |
2298 | |
2299 | auto createDeclValExpr = [&](QualType Ty) -> OpaqueValueExpr { |
2300 | if (Ty->isObjectType() || Ty->isFunctionType()) |
2301 | Ty = SemaRef.Context.getRValueReferenceType(T: Ty); |
2302 | return {Loc, Ty.getNonLValueExprType(Context: SemaRef.Context), |
2303 | Expr::getValueKindForType(T: Ty)}; |
2304 | }; |
2305 | |
2306 | auto LHS = createDeclValExpr(T); |
2307 | auto RHS = createDeclValExpr(U); |
2308 | |
2309 | EnterExpressionEvaluationContext Unevaluated( |
2310 | SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); |
2311 | Sema::ContextRAII TUContext(SemaRef, |
2312 | SemaRef.Context.getTranslationUnitDecl()); |
2313 | SemaRef.BuildBinOp(/*S=*/nullptr, OpLoc: Loc, Opc: BO_Assign, LHSExpr: &LHS, RHSExpr: &RHS); |
2314 | |
2315 | if (!D || D->isInvalidDecl()) |
2316 | return; |
2317 | |
2318 | SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2319 | } |
2320 | |
2321 | static void DiagnoseIsEmptyReason(Sema &S, SourceLocation Loc, |
2322 | const CXXRecordDecl *D) { |
2323 | // Non-static data members (ignore zero-width bit‐fields). |
2324 | for (const auto *Field : D->fields()) { |
2325 | if (Field->isZeroLengthBitField()) |
2326 | continue; |
2327 | if (Field->isBitField()) { |
2328 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2329 | << diag::TraitNotSatisfiedReason::NonZeroLengthField << Field |
2330 | << Field->getSourceRange(); |
2331 | continue; |
2332 | } |
2333 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2334 | << diag::TraitNotSatisfiedReason::NonEmptyMember << Field |
2335 | << Field->getType() << Field->getSourceRange(); |
2336 | } |
2337 | |
2338 | // Virtual functions. |
2339 | for (const auto *M : D->methods()) { |
2340 | if (M->isVirtual()) { |
2341 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2342 | << diag::TraitNotSatisfiedReason::VirtualFunction << M |
2343 | << M->getSourceRange(); |
2344 | break; |
2345 | } |
2346 | } |
2347 | |
2348 | // Virtual bases and non-empty bases. |
2349 | for (const auto &B : D->bases()) { |
2350 | const auto *BR = B.getType()->getAsCXXRecordDecl(); |
2351 | if (!BR || BR->isInvalidDecl()) |
2352 | continue; |
2353 | if (B.isVirtual()) { |
2354 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2355 | << diag::TraitNotSatisfiedReason::VBase << B.getType() |
2356 | << B.getSourceRange(); |
2357 | } |
2358 | if (!BR->isEmpty()) { |
2359 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2360 | << diag::TraitNotSatisfiedReason::NonEmptyBase << B.getType() |
2361 | << B.getSourceRange(); |
2362 | } |
2363 | } |
2364 | } |
2365 | |
2366 | static void DiagnoseIsEmptyReason(Sema &S, SourceLocation Loc, QualType T) { |
2367 | // Emit primary "not empty" diagnostic. |
2368 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait) << T << diag::TraitName::Empty; |
2369 | |
2370 | // While diagnosing is_empty<T>, we want to look at the actual type, not a |
2371 | // reference or an array of it. So we need to massage the QualType param to |
2372 | // strip refs and arrays. |
2373 | if (T->isReferenceType()) |
2374 | S.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2375 | << diag::TraitNotSatisfiedReason::Ref; |
2376 | T = T.getNonReferenceType(); |
2377 | |
2378 | if (auto *AT = S.Context.getAsArrayType(T)) |
2379 | T = AT->getElementType(); |
2380 | |
2381 | if (auto *D = T->getAsCXXRecordDecl()) { |
2382 | if (D->hasDefinition()) { |
2383 | DiagnoseIsEmptyReason(S, Loc, D); |
2384 | S.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2385 | } |
2386 | } |
2387 | } |
2388 | |
2389 | static bool hasMultipleDataBaseClassesWithFields(const CXXRecordDecl *D) { |
2390 | int NumBasesWithFields = 0; |
2391 | for (const CXXBaseSpecifier &Base : D->bases()) { |
2392 | const CXXRecordDecl *BaseRD = Base.getType()->getAsCXXRecordDecl(); |
2393 | if (!BaseRD || BaseRD->isInvalidDecl()) |
2394 | continue; |
2395 | |
2396 | for (const FieldDecl *Field : BaseRD->fields()) { |
2397 | if (!Field->isUnnamedBitField()) { |
2398 | if (++NumBasesWithFields > 1) |
2399 | return true; // found more than one base class with fields |
2400 | break; // no need to check further fields in this base class |
2401 | } |
2402 | } |
2403 | } |
2404 | return false; |
2405 | } |
2406 | |
2407 | static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc, |
2408 | const CXXRecordDecl *D) { |
2409 | for (const CXXBaseSpecifier &B : D->bases()) { |
2410 | assert(B.getType()->getAsCXXRecordDecl() && "invalid base?" ); |
2411 | if (B.isVirtual()) { |
2412 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2413 | << diag::TraitNotSatisfiedReason::VBase << B.getType() |
2414 | << B.getSourceRange(); |
2415 | } |
2416 | if (!B.getType()->isStandardLayoutType()) { |
2417 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2418 | << diag::TraitNotSatisfiedReason::NonStandardLayoutBase << B.getType() |
2419 | << B.getSourceRange(); |
2420 | } |
2421 | } |
2422 | // Check for mixed access specifiers in fields. |
2423 | const FieldDecl *FirstField = nullptr; |
2424 | AccessSpecifier FirstAccess = AS_none; |
2425 | |
2426 | for (const FieldDecl *Field : D->fields()) { |
2427 | if (Field->isUnnamedBitField()) |
2428 | continue; |
2429 | |
2430 | // Record the first field we see |
2431 | if (!FirstField) { |
2432 | FirstField = Field; |
2433 | FirstAccess = Field->getAccess(); |
2434 | continue; |
2435 | } |
2436 | |
2437 | // Check if the field has a different access specifier than the first one. |
2438 | if (Field->getAccess() != FirstAccess) { |
2439 | // Emit a diagnostic about mixed access specifiers. |
2440 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2441 | << diag::TraitNotSatisfiedReason::MixedAccess; |
2442 | |
2443 | SemaRef.Diag(Loc: FirstField->getLocation(), DiagID: diag::note_defined_here) |
2444 | << FirstField; |
2445 | |
2446 | SemaRef.Diag(Loc: Field->getLocation(), DiagID: diag::note_unsatisfied_trait_reason) |
2447 | << diag::TraitNotSatisfiedReason::MixedAccessField << Field |
2448 | << FirstField; |
2449 | |
2450 | // No need to check further fields, as we already found mixed access. |
2451 | break; |
2452 | } |
2453 | } |
2454 | if (hasMultipleDataBaseClassesWithFields(D)) { |
2455 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2456 | << diag::TraitNotSatisfiedReason::MultipleDataBase; |
2457 | } |
2458 | if (D->isPolymorphic()) { |
2459 | // Find the best location to point “defined here” at. |
2460 | const CXXMethodDecl *VirtualMD = nullptr; |
2461 | // First, look for a virtual method. |
2462 | for (const auto *M : D->methods()) { |
2463 | if (M->isVirtual()) { |
2464 | VirtualMD = M; |
2465 | break; |
2466 | } |
2467 | } |
2468 | if (VirtualMD) { |
2469 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2470 | << diag::TraitNotSatisfiedReason::VirtualFunction << VirtualMD; |
2471 | SemaRef.Diag(Loc: VirtualMD->getLocation(), DiagID: diag::note_defined_here) |
2472 | << VirtualMD; |
2473 | } else { |
2474 | // If no virtual method, point to the record declaration itself. |
2475 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2476 | << diag::TraitNotSatisfiedReason::VirtualFunction << D; |
2477 | SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2478 | } |
2479 | } |
2480 | for (const FieldDecl *Field : D->fields()) { |
2481 | if (!Field->getType()->isStandardLayoutType()) { |
2482 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2483 | << diag::TraitNotSatisfiedReason::NonStandardLayoutMember << Field |
2484 | << Field->getType() << Field->getSourceRange(); |
2485 | } |
2486 | } |
2487 | // Find any indirect base classes that have fields. |
2488 | if (D->hasDirectFields()) { |
2489 | const CXXRecordDecl *Indirect = nullptr; |
2490 | D->forallBases(BaseMatches: [&](const CXXRecordDecl *BaseDef) { |
2491 | if (BaseDef->hasDirectFields()) { |
2492 | Indirect = BaseDef; |
2493 | return false; // stop traversal |
2494 | } |
2495 | return true; // continue to the next base |
2496 | }); |
2497 | if (Indirect) { |
2498 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2499 | << diag::TraitNotSatisfiedReason::IndirectBaseWithFields << Indirect |
2500 | << Indirect->getSourceRange(); |
2501 | } |
2502 | } |
2503 | } |
2504 | |
2505 | static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc, |
2506 | QualType T) { |
2507 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait) |
2508 | << T << diag::TraitName::StandardLayout; |
2509 | |
2510 | // Check type-level exclusion first. |
2511 | if (T->isVariablyModifiedType()) { |
2512 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2513 | << diag::TraitNotSatisfiedReason::VLA; |
2514 | return; |
2515 | } |
2516 | |
2517 | if (T->isReferenceType()) { |
2518 | SemaRef.Diag(Loc, DiagID: diag::note_unsatisfied_trait_reason) |
2519 | << diag::TraitNotSatisfiedReason::Ref; |
2520 | return; |
2521 | } |
2522 | T = T.getNonReferenceType(); |
2523 | const CXXRecordDecl *D = T->getAsCXXRecordDecl(); |
2524 | if (!D || D->isInvalidDecl()) |
2525 | return; |
2526 | |
2527 | if (D->hasDefinition()) |
2528 | DiagnoseNonStandardLayoutReason(SemaRef, Loc, D); |
2529 | |
2530 | SemaRef.Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D; |
2531 | } |
2532 | |
2533 | void Sema::DiagnoseTypeTraitDetails(const Expr *E) { |
2534 | E = E->IgnoreParenImpCasts(); |
2535 | if (E->containsErrors()) |
2536 | return; |
2537 | |
2538 | ExtractedTypeTraitInfo TraitInfo = ExtractTypeTraitFromExpression(E); |
2539 | if (!TraitInfo) |
2540 | return; |
2541 | |
2542 | const auto &[Trait, Args] = TraitInfo.value(); |
2543 | switch (Trait) { |
2544 | case UTT_IsCppTriviallyRelocatable: |
2545 | DiagnoseNonTriviallyRelocatableReason(SemaRef&: *this, Loc: E->getBeginLoc(), T: Args[0]); |
2546 | break; |
2547 | case UTT_IsReplaceable: |
2548 | DiagnoseNonReplaceableReason(SemaRef&: *this, Loc: E->getBeginLoc(), T: Args[0]); |
2549 | break; |
2550 | case UTT_IsTriviallyCopyable: |
2551 | DiagnoseNonTriviallyCopyableReason(SemaRef&: *this, Loc: E->getBeginLoc(), T: Args[0]); |
2552 | break; |
2553 | case BTT_IsAssignable: |
2554 | DiagnoseNonAssignableReason(SemaRef&: *this, Loc: E->getBeginLoc(), T: Args[0], U: Args[1]); |
2555 | break; |
2556 | case UTT_IsEmpty: |
2557 | DiagnoseIsEmptyReason(S&: *this, Loc: E->getBeginLoc(), T: Args[0]); |
2558 | break; |
2559 | case UTT_IsStandardLayout: |
2560 | DiagnoseNonStandardLayoutReason(SemaRef&: *this, Loc: E->getBeginLoc(), T: Args[0]); |
2561 | break; |
2562 | default: |
2563 | break; |
2564 | } |
2565 | } |
2566 | |