From 8129c5c0a4eaf202a04d086e56c9f3646fd03721 Mon Sep 17 00:00:00 2001 From: Jeremy Morse Date: Tue, 5 Jun 2018 09:18:26 +0000 Subject: Detect an incompatible VLA pointer assignment For pointer assignments of VLA types, Clang currently detects when array dimensions _lower_ than a variable dimension differ, and reports a warning. However it does not do the same when the _higher_ dimensions differ, a case that GCC does catch. These two pointer types int (*foo)[1][bar][3]; int (*baz)[1][2][3]; are compatible with each another, and the program is well formed if bar == 2, a matter that is the programmers problem. However the following: int (*qux)[2][2][3]; would not be compatible with either, because the upper dimension differs in size. Clang reports baz is incompatible with qux, but not that foo is incompatible with qux because it doesn't check those higher dimensions. Fix this by comparing array sizes on higher dimensions: if both are constants but unequal then report incompatibility; if either dimension is variable then we can't know either way. Differential Revision: https://reviews.llvm.org/D47628 llvm-svn: 333989 --- clang/lib/AST/ASTContext.cpp | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'clang/lib/AST/ASTContext.cpp') diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4956710b4f5..c759c96be5b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8601,6 +8601,38 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, QualType ResultType = mergeTypes(LHSElem, RHSElem, false, Unqualified); if (ResultType.isNull()) return {}; + + const VariableArrayType* LVAT = getAsVariableArrayType(LHS); + const VariableArrayType* RVAT = getAsVariableArrayType(RHS); + + // If either side is a variable array, and both are complete, check whether + // the current dimension is definite. + if (LVAT || RVAT) { + auto SizeFetch = [this](const VariableArrayType* VAT, + const ConstantArrayType* CAT) + -> std::pair { + if (VAT) { + llvm::APSInt TheInt; + Expr *E = VAT->getSizeExpr(); + if (E && E->isIntegerConstantExpr(TheInt, *this)) + return std::make_pair(true, TheInt); + else + return std::make_pair(false, TheInt); + } else if (CAT) { + return std::make_pair(true, CAT->getSize()); + } else { + return std::make_pair(false, llvm::APInt()); + } + }; + + bool HaveLSize, HaveRSize; + llvm::APInt LSize, RSize; + std::tie(HaveLSize, LSize) = SizeFetch(LVAT, LCAT); + std::tie(HaveRSize, RSize) = SizeFetch(RVAT, RCAT); + if (HaveLSize && HaveRSize && !llvm::APInt::isSameValue(LSize, RSize)) + return {}; // Definite, but unequal, array dimension + } + if (LCAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType)) @@ -8609,8 +8641,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, ArrayType::ArraySizeModifier(), 0); if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(), ArrayType::ArraySizeModifier(), 0); - const VariableArrayType* LVAT = getAsVariableArrayType(LHS); - const VariableArrayType* RVAT = getAsVariableArrayType(RHS); if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType)) -- cgit v1.2.3