|
30 | 30 | #include "clang/AST/NSAPI.h"
|
31 | 31 | #include "clang/AST/NonTrivialTypeVisitor.h"
|
32 | 32 | #include "clang/AST/OperationKinds.h"
|
| 33 | +#include "clang/AST/RecordLayout.h" |
33 | 34 | #include "clang/AST/Stmt.h"
|
34 | 35 | #include "clang/AST/TemplateBase.h"
|
35 | 36 | #include "clang/AST/Type.h"
|
@@ -13105,17 +13106,226 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
|
13105 | 13106 | return HasInvalidParm;
|
13106 | 13107 | }
|
13107 | 13108 |
|
13108 |
| -/// A helper function to get the alignment of a Decl referred to by DeclRefExpr |
13109 |
| -/// or MemberExpr. |
13110 |
| -static CharUnits getDeclAlign(Expr *E, CharUnits TypeAlign, |
13111 |
| - ASTContext &Context) { |
13112 |
| - if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) |
13113 |
| - return Context.getDeclAlign(DRE->getDecl()); |
| 13109 | +Optional<std::pair<CharUnits, CharUnits>> |
| 13110 | +static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx); |
| 13111 | + |
| 13112 | +/// Compute the alignment and offset of the base class object given the |
| 13113 | +/// derived-to-base cast expression and the alignment and offset of the derived |
| 13114 | +/// class object. |
| 13115 | +static std::pair<CharUnits, CharUnits> |
| 13116 | +getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType, |
| 13117 | + CharUnits BaseAlignment, CharUnits Offset, |
| 13118 | + ASTContext &Ctx) { |
| 13119 | + for (auto PathI = CE->path_begin(), PathE = CE->path_end(); PathI != PathE; |
| 13120 | + ++PathI) { |
| 13121 | + const CXXBaseSpecifier *Base = *PathI; |
| 13122 | + const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); |
| 13123 | + if (Base->isVirtual()) { |
| 13124 | + // The complete object may have a lower alignment than the non-virtual |
| 13125 | + // alignment of the base, in which case the base may be misaligned. Choose |
| 13126 | + // the smaller of the non-virtual alignment and BaseAlignment, which is a |
| 13127 | + // conservative lower bound of the complete object alignment. |
| 13128 | + CharUnits NonVirtualAlignment = |
| 13129 | + Ctx.getASTRecordLayout(BaseDecl).getNonVirtualAlignment(); |
| 13130 | + BaseAlignment = std::min(BaseAlignment, NonVirtualAlignment); |
| 13131 | + Offset = CharUnits::Zero(); |
| 13132 | + } else { |
| 13133 | + const ASTRecordLayout &RL = |
| 13134 | + Ctx.getASTRecordLayout(DerivedType->getAsCXXRecordDecl()); |
| 13135 | + Offset += RL.getBaseClassOffset(BaseDecl); |
| 13136 | + } |
| 13137 | + DerivedType = Base->getType(); |
| 13138 | + } |
| 13139 | + |
| 13140 | + return std::make_pair(BaseAlignment, Offset); |
| 13141 | +} |
| 13142 | + |
| 13143 | +/// Compute the alignment and offset of a binary additive operator. |
| 13144 | +static Optional<std::pair<CharUnits, CharUnits>> |
| 13145 | +getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE, |
| 13146 | + bool IsSub, ASTContext &Ctx) { |
| 13147 | + QualType PointeeType = PtrE->getType()->getPointeeType(); |
| 13148 | + |
| 13149 | + if (!PointeeType->isConstantSizeType()) |
| 13150 | + return llvm::None; |
| 13151 | + |
| 13152 | + auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx); |
| 13153 | + |
| 13154 | + if (!P) |
| 13155 | + return llvm::None; |
13114 | 13156 |
|
13115 |
| - if (const auto *ME = dyn_cast<MemberExpr>(E)) |
13116 |
| - return Context.getDeclAlign(ME->getMemberDecl()); |
| 13157 | + llvm::APSInt IdxRes; |
| 13158 | + CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType); |
| 13159 | + if (IntE->isIntegerConstantExpr(IdxRes, Ctx)) { |
| 13160 | + CharUnits Offset = EltSize * IdxRes.getExtValue(); |
| 13161 | + if (IsSub) |
| 13162 | + Offset = -Offset; |
| 13163 | + return std::make_pair(P->first, P->second + Offset); |
| 13164 | + } |
13117 | 13165 |
|
13118 |
| - return TypeAlign; |
| 13166 | + // If the integer expression isn't a constant expression, compute the lower |
| 13167 | + // bound of the alignment using the alignment and offset of the pointer |
| 13168 | + // expression and the element size. |
| 13169 | + return std::make_pair( |
| 13170 | + P->first.alignmentAtOffset(P->second).alignmentAtOffset(EltSize), |
| 13171 | + CharUnits::Zero()); |
| 13172 | +} |
| 13173 | + |
| 13174 | +/// This helper function takes an lvalue expression and returns the alignment of |
| 13175 | +/// a VarDecl and a constant offset from the VarDecl. |
| 13176 | +Optional<std::pair<CharUnits, CharUnits>> |
| 13177 | +static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) { |
| 13178 | + E = E->IgnoreParens(); |
| 13179 | + switch (E->getStmtClass()) { |
| 13180 | + default: |
| 13181 | + break; |
| 13182 | + case Stmt::CStyleCastExprClass: |
| 13183 | + case Stmt::CXXStaticCastExprClass: |
| 13184 | + case Stmt::ImplicitCastExprClass: { |
| 13185 | + auto *CE = cast<CastExpr>(E); |
| 13186 | + const Expr *From = CE->getSubExpr(); |
| 13187 | + switch (CE->getCastKind()) { |
| 13188 | + default: |
| 13189 | + break; |
| 13190 | + case CK_NoOp: |
| 13191 | + return getBaseAlignmentAndOffsetFromLValue(From, Ctx); |
| 13192 | + case CK_UncheckedDerivedToBase: |
| 13193 | + case CK_DerivedToBase: { |
| 13194 | + auto P = getBaseAlignmentAndOffsetFromLValue(From, Ctx); |
| 13195 | + if (!P) |
| 13196 | + break; |
| 13197 | + return getDerivedToBaseAlignmentAndOffset(CE, From->getType(), P->first, |
| 13198 | + P->second, Ctx); |
| 13199 | + } |
| 13200 | + } |
| 13201 | + break; |
| 13202 | + } |
| 13203 | + case Stmt::ArraySubscriptExprClass: { |
| 13204 | + auto *ASE = cast<ArraySubscriptExpr>(E); |
| 13205 | + return getAlignmentAndOffsetFromBinAddOrSub(ASE->getBase(), ASE->getIdx(), |
| 13206 | + false, Ctx); |
| 13207 | + } |
| 13208 | + case Stmt::DeclRefExprClass: { |
| 13209 | + if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { |
| 13210 | + // FIXME: If VD is captured by copy or is an escaping __block variable, |
| 13211 | + // use the alignment of VD's type. |
| 13212 | + if (!VD->getType()->isReferenceType()) |
| 13213 | + return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero()); |
| 13214 | + if (VD->hasInit()) |
| 13215 | + return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx); |
| 13216 | + } |
| 13217 | + break; |
| 13218 | + } |
| 13219 | + case Stmt::MemberExprClass: { |
| 13220 | + auto *ME = cast<MemberExpr>(E); |
| 13221 | + if (ME->isArrow()) |
| 13222 | + break; |
| 13223 | + auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); |
| 13224 | + if (!FD || FD->getType()->isReferenceType()) |
| 13225 | + break; |
| 13226 | + auto P = getBaseAlignmentAndOffsetFromLValue(ME->getBase(), Ctx); |
| 13227 | + if (!P) |
| 13228 | + break; |
| 13229 | + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent()); |
| 13230 | + uint64_t Offset = Layout.getFieldOffset(FD->getFieldIndex()); |
| 13231 | + return std::make_pair(P->first, |
| 13232 | + P->second + CharUnits::fromQuantity(Offset)); |
| 13233 | + } |
| 13234 | + case Stmt::UnaryOperatorClass: { |
| 13235 | + auto *UO = cast<UnaryOperator>(E); |
| 13236 | + switch (UO->getOpcode()) { |
| 13237 | + default: |
| 13238 | + break; |
| 13239 | + case UO_Deref: |
| 13240 | + return getBaseAlignmentAndOffsetFromPtr(UO->getSubExpr(), Ctx); |
| 13241 | + } |
| 13242 | + break; |
| 13243 | + } |
| 13244 | + case Stmt::BinaryOperatorClass: { |
| 13245 | + auto *BO = cast<BinaryOperator>(E); |
| 13246 | + auto Opcode = BO->getOpcode(); |
| 13247 | + switch (Opcode) { |
| 13248 | + default: |
| 13249 | + break; |
| 13250 | + case BO_Comma: |
| 13251 | + return getBaseAlignmentAndOffsetFromLValue(BO->getRHS(), Ctx); |
| 13252 | + } |
| 13253 | + break; |
| 13254 | + } |
| 13255 | + } |
| 13256 | + return llvm::None; |
| 13257 | +} |
| 13258 | + |
| 13259 | +/// This helper function takes a pointer expression and returns the alignment of |
| 13260 | +/// a VarDecl and a constant offset from the VarDecl. |
| 13261 | +Optional<std::pair<CharUnits, CharUnits>> |
| 13262 | +static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) { |
| 13263 | + E = E->IgnoreParens(); |
| 13264 | + switch (E->getStmtClass()) { |
| 13265 | + default: |
| 13266 | + break; |
| 13267 | + case Stmt::CStyleCastExprClass: |
| 13268 | + case Stmt::CXXStaticCastExprClass: |
| 13269 | + case Stmt::ImplicitCastExprClass: { |
| 13270 | + auto *CE = cast<CastExpr>(E); |
| 13271 | + const Expr *From = CE->getSubExpr(); |
| 13272 | + switch (CE->getCastKind()) { |
| 13273 | + default: |
| 13274 | + break; |
| 13275 | + case CK_NoOp: |
| 13276 | + return getBaseAlignmentAndOffsetFromPtr(From, Ctx); |
| 13277 | + case CK_ArrayToPointerDecay: |
| 13278 | + return getBaseAlignmentAndOffsetFromLValue(From, Ctx); |
| 13279 | + case CK_UncheckedDerivedToBase: |
| 13280 | + case CK_DerivedToBase: { |
| 13281 | + auto P = getBaseAlignmentAndOffsetFromPtr(From, Ctx); |
| 13282 | + if (!P) |
| 13283 | + break; |
| 13284 | + return getDerivedToBaseAlignmentAndOffset( |
| 13285 | + CE, From->getType()->getPointeeType(), P->first, P->second, Ctx); |
| 13286 | + } |
| 13287 | + } |
| 13288 | + break; |
| 13289 | + } |
| 13290 | + case Stmt::UnaryOperatorClass: { |
| 13291 | + auto *UO = cast<UnaryOperator>(E); |
| 13292 | + if (UO->getOpcode() == UO_AddrOf) |
| 13293 | + return getBaseAlignmentAndOffsetFromLValue(UO->getSubExpr(), Ctx); |
| 13294 | + break; |
| 13295 | + } |
| 13296 | + case Stmt::BinaryOperatorClass: { |
| 13297 | + auto *BO = cast<BinaryOperator>(E); |
| 13298 | + auto Opcode = BO->getOpcode(); |
| 13299 | + switch (Opcode) { |
| 13300 | + default: |
| 13301 | + break; |
| 13302 | + case BO_Add: |
| 13303 | + case BO_Sub: { |
| 13304 | + const Expr *LHS = BO->getLHS(), *RHS = BO->getRHS(); |
| 13305 | + if (Opcode == BO_Add && !RHS->getType()->isIntegralOrEnumerationType()) |
| 13306 | + std::swap(LHS, RHS); |
| 13307 | + return getAlignmentAndOffsetFromBinAddOrSub(LHS, RHS, Opcode == BO_Sub, |
| 13308 | + Ctx); |
| 13309 | + } |
| 13310 | + case BO_Comma: |
| 13311 | + return getBaseAlignmentAndOffsetFromPtr(BO->getRHS(), Ctx); |
| 13312 | + } |
| 13313 | + break; |
| 13314 | + } |
| 13315 | + } |
| 13316 | + return llvm::None; |
| 13317 | +} |
| 13318 | + |
| 13319 | +static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) { |
| 13320 | + // See if we can compute the alignment of a VarDecl and an offset from it. |
| 13321 | + Optional<std::pair<CharUnits, CharUnits>> P = |
| 13322 | + getBaseAlignmentAndOffsetFromPtr(E, S.Context); |
| 13323 | + |
| 13324 | + if (P) |
| 13325 | + return P->first.alignmentAtOffset(P->second); |
| 13326 | + |
| 13327 | + // If that failed, return the type's alignment. |
| 13328 | + return S.Context.getTypeAlignInChars(E->getType()->getPointeeType()); |
13119 | 13329 | }
|
13120 | 13330 |
|
13121 | 13331 | /// CheckCastAlign - Implements -Wcast-align, which warns when a
|
@@ -13151,15 +13361,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
|
13151 | 13361 | // includes 'void'.
|
13152 | 13362 | if (SrcPointee->isIncompleteType()) return;
|
13153 | 13363 |
|
13154 |
| - CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee); |
13155 |
| - |
13156 |
| - if (auto *CE = dyn_cast<CastExpr>(Op)) { |
13157 |
| - if (CE->getCastKind() == CK_ArrayToPointerDecay) |
13158 |
| - SrcAlign = getDeclAlign(CE->getSubExpr(), SrcAlign, Context); |
13159 |
| - } else if (auto *UO = dyn_cast<UnaryOperator>(Op)) { |
13160 |
| - if (UO->getOpcode() == UO_AddrOf) |
13161 |
| - SrcAlign = getDeclAlign(UO->getSubExpr(), SrcAlign, Context); |
13162 |
| - } |
| 13364 | + CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this); |
13163 | 13365 |
|
13164 | 13366 | if (SrcAlign >= DestAlign) return;
|
13165 | 13367 |
|
|
0 commit comments