diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-07-11 00:19:19 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-07-11 00:19:19 +0000 |
commit | 94b6962816b6a29006a598388580edab874a4d66 (patch) | |
tree | ed10dcfcf4dde9a639d9eb51834433cbe719a4ab /clang/lib/AST/ASTContext.cpp | |
parent | 911674201ac3a174881c69ac803640f194b17f80 (diff) |
DR330: look through array types when forming the cv-decomposition of a type.
This allows more qualification conversions, eg. conversion from
'int *(*)[]' -> 'const int *const (*)[]'
is now permitted, along with all the consequences of that: more types
are similar, more cases are permitted by const_cast, and conversely,
fewer "casting away constness" cases are permitted by reinterpret_cast.
Diffstat (limited to 'clang/lib/AST/ASTContext.cpp')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 83 |
1 files changed, 74 insertions, 9 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index ca54d8f6759..832f3a2e7a5 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4965,15 +4965,49 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type, SourceRange()); } -/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that -/// may be similar (C++ 4.4), replaces T1 and T2 with the type that -/// they point to and return true. If T1 and T2 aren't pointer types -/// or pointer-to-member types, or if they are not similar at this -/// level, returns false and leaves T1 and T2 unchanged. Top-level -/// qualifiers on T1 and T2 are ignored. This function will typically -/// be called in a loop that successively "unwraps" pointer and -/// pointer-to-member types to compare them at each level. -bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { +/// Attempt to unwrap two types that may both be array types with the same bound +/// (or both be array types of unknown bound) for the purpose of comparing the +/// cv-decomposition of two types per C++ [conv.qual]. +static void unwrapSimilarArrayTypes(ASTContext &Ctx, QualType &T1, + QualType &T2) { + while (true) { + auto *AT1 = Ctx.getAsArrayType(T1); + if (!AT1) return; + + auto *AT2 = Ctx.getAsArrayType(T2); + if (!AT2) return; + + // If we don't have two array types with the same constant bound nor two + // incomplete array types, we've unwrapped everything we can. + if (auto *CAT1 = dyn_cast<ConstantArrayType>(AT1)) { + auto *CAT2 = dyn_cast<ConstantArrayType>(AT2); + if (!CAT2 || CAT1->getSize() != CAT2->getSize()) + return; + } else if (!isa<IncompleteArrayType>(AT1) || + !isa<IncompleteArrayType>(AT2)) { + return; + } + + T1 = AT1->getElementType(); + T2 = AT2->getElementType(); + } +} + +/// Attempt to unwrap two types that may be similar (C++ [conv.qual]). +/// +/// If T1 and T2 are both pointer types of the same kind, or both array types +/// with the same bound, unwraps layers from T1 and T2 until a pointer type is +/// unwrapped. Top-level qualifiers on T1 and T2 are ignored. +/// +/// This function will typically be called in a loop that successively +/// "unwraps" pointer and pointer-to-member types to compare them at each +/// level. +/// +/// \return \c true if a pointer type was unwrapped, \c false if we reached a +/// pair of types that can't be unwrapped further. +bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2) { + unwrapSimilarArrayTypes(*this, T1, T2); + const auto *T1PtrType = T1->getAs<PointerType>(); const auto *T2PtrType = T2->getAs<PointerType>(); if (T1PtrType && T2PtrType) { @@ -5007,6 +5041,37 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { return false; } +bool ASTContext::hasSimilarType(QualType T1, QualType T2) { + while (true) { + Qualifiers Quals; + T1 = getUnqualifiedArrayType(T1, Quals); + T2 = getUnqualifiedArrayType(T2, Quals); + if (hasSameType(T1, T2)) + return true; + if (!UnwrapSimilarTypes(T1, T2)) + return false; + } +} + +bool ASTContext::hasCvrSimilarType(QualType T1, QualType T2) { + while (true) { + Qualifiers Quals1, Quals2; + T1 = getUnqualifiedArrayType(T1, Quals1); + T2 = getUnqualifiedArrayType(T2, Quals2); + + Quals1.removeCVRQualifiers(); + Quals2.removeCVRQualifiers(); + if (Quals1 != Quals2) + return false; + + if (hasSameType(T1, T2)) + return true; + + if (!UnwrapSimilarTypes(T1, T2)) + return false; + } +} + DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const { |