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