================
@@ -10057,6 +10058,76 @@ static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl
*FD,
}
}
+void Sema::DiagnoseVlaSizeParameter(
+ const SmallVector<ParmVarDecl *, 16> &Params) {
+ // Loop over the parameters to see if any of the size expressions contains
+ // a DeclRefExpr which refers to a variable from an outer scope that is
+ // also named later in the parameter list.
+ // e.g., int n; void func(int array[n], int n);
+ SmallVector<const DeclRefExpr *, 2> DRESizeExprs;
+ llvm::for_each(Params, [&](const ParmVarDecl *Param) {
+ // If we have any size expressions we need to check against, check them
+ // now.
+ for (const auto *DRE : DRESizeExprs) {
+ // Check to see if this parameter has the same name as one of the
+ // DeclRefExprs we wanted to test against. If so, then we found a
+ // situation where an earlier parameter refers to the name of a later
+ // parameter, which is (currently) only valid if there's a variable
+ // from an outer scope with the same name.
+ if (const auto *SizeExprND = dyn_cast<NamedDecl>(DRE->getDecl());
+ SizeExprND && SizeExprND->getIdentifier() == Param->getIdentifier())
{
+ // Diagnose the DeclRefExpr from the parameter with the size
+ // expression.
+ Diag(DRE->getLocation(), diag::warn_vla_size_expr_shadow);
+ // Note the parameter that a user could be confused into thinking
+ // they're referring to.
+ Diag(Param->getLocation(), diag::note_vla_size_expr_shadow_param);
+ // Note the DeclRefExpr that's actually being used.
+ Diag(DRE->getDecl()->getLocation(),
+ diag::note_vla_size_expr_shadow_actual);
+ }
+ }
+
+ // To check whether its size expression is a simple DeclRefExpr, we first
+ // have to walk through pointers or references, but array types always
+ // decay to a pointer, so skip if this is a DecayedType.
+ QualType QT = Param->getType();
+ while (!isa<DecayedType>(QT.getTypePtr()) &&
+ (QT->isPointerType() || QT->isReferenceType()))
+ QT = QT->getPointeeType();
+
+ // An array type is always decayed to a pointer, so we need to get the
+ // original type in that case.
+ if (const auto *DT = QT->getAs<DecayedType>())
+ QT = DT->getOriginalType();
+
+ // Now we can see if it's a VLA type with a size expression.
+ // FIXME: it would be nice to handle constant-sized arrays as well,
+ // e.g., constexpr int n = 12; void foo(int array[n], int n);
+ // however, the constant expression is replaced by its value at the time
+ // we form the type, so we've lost that information here.
+ if (!QT->hasSizedVLAType())
+ return;
+
+ const VariableArrayType *VAT = getASTContext().getAsVariableArrayType(QT);
+ if (!VAT)
+ return;
+
+ class DeclRefFinder : public ConstDynamicRecursiveASTVisitor {
+ SmallVectorImpl<const DeclRefExpr *> &Found;
+
+ public:
+ DeclRefFinder(SmallVectorImpl<const DeclRefExpr *> &Found)
+ : Found(Found) {}
+ bool VisitDeclRefExpr(const DeclRefExpr *DRE) override {
+ Found.push_back(DRE);
----------------
rapidsna wrote:
Per @cor3ntin's earlier comment
https://github.com/llvm/llvm-project/pull/129772/changes#r1980917819, we don't
want to warn at `int foo[::a], int a`. You may want to check if `DeclRefExpr`
has `NestedNameSpecifier` using `hasQualifier()` and add to `Found` only when
`!DRE->hasQualifier()`.
Also, add the test.
https://github.com/llvm/llvm-project/pull/181550
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits