Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -850,6 +850,9 @@ return getMostRecentDecl(); } + /// \brief Whether this variable has non-const use so it can't be const. + unsigned NonConstUse:1; + public: typedef redeclarable_base::redecl_range redecl_range; typedef redeclarable_base::redecl_iterator redecl_iterator; @@ -865,6 +868,13 @@ IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S); + /// \brief Whether the declared symbol has non-const usage so it can't be + /// const. + bool hasNonConstUse() const { return NonConstUse; } + + /// \brief Use this method when this symbol can't be const. + void setNonConstUse() { NonConstUse = isThisDeclarationReferenced(); } + static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID); SourceRange getSourceRange() const override LLVM_READONLY; Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -434,6 +434,7 @@ def UnusedLabel : DiagGroup<"unused-label">; def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedResult : DiagGroup<"unused-result">; +def NonConstParameter : DiagGroup<"nonconst-parameter">; def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">; def UnevaluatedExpression : DiagGroup<"unevaluated-expression", [PotentiallyEvaluatedExpression]>; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -197,6 +197,8 @@ def err_parameter_name_omitted : Error<"parameter name omitted">; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup, DefaultIgnore; +def warn_nonconst_parameter : Warning<"parameter %0 can be const">, + InGroup; def warn_unused_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; def warn_unused_local_typedef : Warning< Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1762,6 +1762,11 @@ void DiagnoseUnusedParameters(ParmVarDecl * const *Begin, ParmVarDecl * const *End); + /// \brief Diagnose pointer parameters that should be const in the given + /// sequence of ParmVarDecl pointers. + void DiagnoseNonConstPointerParameters(ParmVarDecl * const *Begin, + ParmVarDecl * const *End); + /// \brief Diagnose whether the size of parameters or return value of a /// function or obj-c method definition is pass-by-value and larger than a /// specified threshold. @@ -3560,6 +3565,12 @@ void MarkDeclRefReferenced(DeclRefExpr *E); void MarkMemberReferenced(MemberExpr *E); + /// \brief Mark pointers in l-value expression as NonConstUse. + static void MarkLNonConstUse(Expr *E); + + /// \brief Mark pointers in r-value expression as NonConstUse. + static void MarkRNonConstUse(Expr *E); + void UpdateMarkingForLValueToRValue(Expr *E); void CleanupVarDeclMarking(); Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1762,7 +1762,7 @@ IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass SC) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), - redeclarable_base(C), Init() { + redeclarable_base(C), Init(), NonConstUse(false) { static_assert(sizeof(VarDeclBitfields) <= sizeof(unsigned), "VarDeclBitfields too large!"); static_assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned), Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -2020,6 +2020,16 @@ ExprResult Init(ParseInitializer()); + if (ThisDecl && !Init.isInvalid()) { + if (const auto *VD = dyn_cast(ThisDecl)) { + const Type *T = VD->getType().getTypePtrOrNull(); + if (T && (!T->isPointerType() || + !T->getPointeeType().isConstQualified())) { + Sema::MarkRNonConstUse(Init.get()); + } + } + } + // If this is the only decl in (possibly) range based for statement, // our best guess is that the user meant ':' instead of '='. if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) { Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -167,7 +167,19 @@ ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, isTypeCast); - return ParseRHSOfBinaryExpression(LHS, prec::Assignment); + + ExprResult ER(ParseRHSOfBinaryExpression(LHS, prec::Assignment)); + if (ER.isInvalid()) + return ER; + + Expr *E = ER.get()->IgnoreParenCasts(); + if (auto *B = dyn_cast(E)) { + if (B->isAssignmentOp()) + Sema::MarkRNonConstUse(E); + } else if (isa(E) || isa(E)) { + Sema::MarkRNonConstUse(E); + } + return ER; } /// \brief Parse an assignment expression where part of an Objective-C message @@ -408,6 +420,9 @@ if (TernaryMiddle.isUsable()) TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); + } else if (auto *B = dyn_cast(RHS.get())) { + if (B->isAssignmentOp()) + Sema::MarkRNonConstUse(B->getRHS()); } NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, @@ -1543,6 +1558,8 @@ LHS = Actions.ActOnCallExpr(getCurScope(), LHS.get(), Loc, ArgExprs, Tok.getLocation(), ExecConfig); + if (!LHS.isInvalid()) + Sema::MarkRNonConstUse(LHS.get()); PT.consumeClose(); } Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -389,6 +389,9 @@ return Actions.ActOnExprStmtError(); } + // Mark pointers in the expression as nonconstused. + Sema::MarkRNonConstUse(Expr.get()); + if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && Actions.CheckCaseExpression(Expr.get())) { // If a constant expression is followed by a colon inside a switch block, @@ -954,6 +957,19 @@ StmtResult R; if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(Stmts, false); + if (!R.isInvalid() && R.get()) { + if (ReturnStmt *RS = dyn_cast(R.get())) { + if (RS->getRetValue()) { + if (auto *Cast = dyn_cast(RS->getRetValue())) { + const Type *T = Cast->getType().getTypePtr(); + if (T->isPointerType() && + !T->getPointeeType().isConstQualified()) { + Sema::MarkRNonConstUse(Cast); + } + } + } + } + } } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here @@ -1825,6 +1841,14 @@ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); return StmtError(); } + // If function returns a nonconst pointer then pointers used in the return + // expression can't be const. + if (const FunctionDecl *FD = Actions.getCurFunctionDecl()) { + const Type *FnRetType = FD->getReturnType().getTypePtr(); + if (FnRetType && FnRetType->isPointerType() && + !FnRetType->getPointeeType().isConstQualified()) + Sema::MarkRNonConstUse(R.get()); + } } return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope()); } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8987,6 +8987,12 @@ return; } + if (const auto *VD = dyn_cast(RealDecl)) { + const Type *T = VD->getType().getTypePtrOrNull(); + if (T && (!T->isPointerType() || !T->getPointeeType().isConstQualified())) + MarkLNonConstUse(Init); + } + if (CXXMethodDecl *Method = dyn_cast(RealDecl)) { // Pure-specifiers are handled in ActOnPureSpecifier. Diag(Method->getLocation(), diag::err_member_function_initialization) @@ -10398,6 +10404,46 @@ } } +void Sema::DiagnoseNonConstPointerParameters(ParmVarDecl * const *ParamBegin, + ParmVarDecl * const *ParamEnd) { + // Don't diagnose nonconst-parameter errors in template instantiations + if (!ActiveTemplateInstantiations.empty()) + return; + for (const auto *Param : llvm::make_range(ParamBegin, ParamEnd)) { + if (!Param->isReferenced() || Param->hasNonConstUse()) + continue; + const Type *T = Param->getType().getTypePtr(); + if (!T->isPointerType()) + continue; + if (T->getPointeeType().isConstQualified()) + continue; + // Don't warn about function pointers. + if (T->getPointeeType().getTypePtr()->isFunctionProtoType()) + continue; + // Don't warn about struct parameters. These are not handled properly by + // the code currently. There should not be warnings always when a struct + // pointer parameter can be const neither. + if (T->getPointeeType().getTypePtr()->isRecordType()) + continue; + // Don't warn about ** parameters. These are not handled properly by the + // code currently. + if (T->getPointeeType().getTypePtr()->isArrayType()) + continue; + if (T->getPointeeType().getTypePtr()->isPointerType()) + continue; + // Don't warn about void * as such parameters are often used in casts that + // are hard to handle well. For now there are no warnings about such + // parameters. + if (T->getPointeeType().getTypePtr()->isVoidType()) + continue; + // Don't warn about _Atomic parameters + if (T->getPointeeType().getTypePtr()->isAtomicType()) + continue; + Diag(Param->getLocation(), diag::warn_nonconst_parameter) + << Param->getDeclName(); + } +} + void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd, QualType ReturnTy, @@ -10970,6 +11016,8 @@ // Don't diagnose unused parameters of defaulted or deleted functions. if (!FD->isDeleted() && !FD->isDefaulted()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); + if (!getLangOpts().CPlusPlus) + DiagnoseNonConstPointerParameters(FD->param_begin(), FD->param_end()); DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), FD->getReturnType(), FD); @@ -10978,7 +11026,7 @@ MarkVTableUsed(FD->getLocation(), Constructor->getParent()); else if (CXXDestructorDecl *Destructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Destructor->getParent()); - + // Try to apply the named return value optimization. We have to check // if we can do this here because lambdas keep return statements around // to deduce an implicit return type. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -9502,6 +9502,8 @@ if (CheckForModifiableLvalue(LHSExpr, Loc, *this)) return QualType(); + MarkLNonConstUse(LHSExpr); + QualType LHSType = LHSExpr->getType(); QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType; @@ -12807,7 +12809,8 @@ CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); - Var->setReferenced(true); + Var->setReferenced(); + Var->setNonConstUse(); Var->markUsed(S.Context); } @@ -14541,3 +14544,105 @@ return new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc); } + +/// \brief Mark variables in l-value expression as nonconstuse +void Sema::MarkLNonConstUse(Expr *E) { + E = E->IgnoreParenCasts(); + if (auto *B = dyn_cast(E)) { + if (B->isAdditiveOp()) { + // p + 2 + MarkLNonConstUse(B->getLHS()); + MarkLNonConstUse(B->getRHS()); + } else if (B->isAssignmentOp()) { + MarkLNonConstUse(B->getLHS()); + MarkRNonConstUse(B->getRHS()); + } + } else if (auto *D = dyn_cast(E)) { + if (auto *VD = dyn_cast(D->getDecl())) + VD->setNonConstUse(); + } else if (auto *U = dyn_cast(E)) { + MarkLNonConstUse(U->getSubExpr()); + } else if (auto *A = dyn_cast(E)) { + MarkLNonConstUse(A->getBase()); + } +} + +/// Mark variables in r-value expression as nonconstuse. Taking address of +/// pointer is nonconstuse 'x=p' but dereferencing pointer is not nonconstuse +/// 'x = *p;' +void Sema::MarkRNonConstUse(Expr *E) { + E = E->IgnoreParenCasts(); + if (auto *B = dyn_cast(E)) { + if (B->isAdditiveOp()) { + // p + 2 + MarkRNonConstUse(B->getLHS()); + MarkRNonConstUse(B->getRHS()); + } else if (B->isAssignmentOp()) { + MarkLNonConstUse(B->getLHS()); + // If LHS is nonconst then mark RHS as nonconstuse + const Type *T = B->getLHS()->getType().getTypePtr(); + if (T && T->isPointerType() && !T->getPointeeType().isConstQualified()) + MarkRNonConstUse(B->getRHS()); + } + } else if (auto *ILE = dyn_cast(E)) { + for (auto *I : llvm::make_range(ILE->getInits(), + ILE->getInits() + ILE->getNumInits())) + MarkRNonConstUse(I); + } else if (auto *CE = dyn_cast(E)) { + // Mark nonconst function parameters as written. + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD || FD->isVariadic()) { + // Mark all arguments as written + // TODO: Handle CXXMemberCallExpr better + for (auto *Arg : CE->arguments()) { + MarkRNonConstUse(Arg); + } + return; + } + unsigned ArgNr = 0U; + for (const auto *Par : FD->parameters()) { + if (ArgNr >= CE->getNumArgs()) + break; + // Is this a nonconstant pointer/reference parameter? + const Type *ParType = Par->getType().getTypePtr(); + if ((ParType->isPointerType() && + !ParType->getPointeeType().isConstQualified()) || + (ParType->isReferenceType() && !Par->getType().isConstQualified()) || + (ParType->isRecordType() && !Par->getType().isConstQualified())) { + // This is a nonconst pointer/reference parameter, the data is + // potentially written in the function. + Expr *Arg = CE->getArg(ArgNr); + if (ParType->isReferenceType()) { + if (auto *U = dyn_cast(Arg)) + Arg = U->getSubExpr(); + } else if (auto *CE = + dyn_cast(Arg->IgnoreParenCasts())) { + MarkRNonConstUse(CE->getInitializer()); + return; + } + MarkRNonConstUse(Arg); + } + ArgNr++; + } + } else if (auto *B = dyn_cast(E)) { + MarkRNonConstUse(B->getCommon()); + MarkRNonConstUse(B->getFalseExpr()); + } else if (auto *C = dyn_cast(E)) { + MarkRNonConstUse(C->getTrueExpr()); + MarkRNonConstUse(C->getFalseExpr()); + } else if (auto *D = dyn_cast(E)) { + if (auto *VD = dyn_cast(D->getDecl())) + VD->setNonConstUse(); + } else if (auto *U = dyn_cast(E)) { + if (U->getOpcode() == UO_Deref) + return; + E = U->getSubExpr()->IgnoreParenCasts(); + if (auto *A = dyn_cast(E)) + E = A->getBase(); + else if (auto *U = dyn_cast(E)) { + if (U->getOpcode() == UO_Deref) + E = U->getSubExpr()->IgnoreParenCasts(); + } + MarkRNonConstUse(E); + } +} Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -815,7 +815,8 @@ VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc, Loc, Id, InitCaptureType, TSI, SC_Auto); NewVD->setInitCapture(true); - NewVD->setReferenced(true); + NewVD->setReferenced(); + NewVD->setNonConstUse(); NewVD->markUsed(Context); NewVD->setInit(Init); return NewVD; Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -499,6 +499,7 @@ SourceLocation Loc, bool RefersToCapture = false) { D->setReferenced(); + D->setNonConstUse(); D->markUsed(S.Context); return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), D, RefersToCapture, Loc, Ty, Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3632,6 +3632,7 @@ if (OldVar->isUsed(false)) NewVar->setIsUsed(); NewVar->setReferenced(OldVar->isReferenced()); + NewVar->setNonConstUse(); } InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -501,6 +501,8 @@ D->setImplicit(Record[Idx++]); D->Used = Record[Idx++]; D->setReferenced(Record[Idx++]); + if (auto *VD = dyn_cast(D)) + VD->setNonConstUse(); D->setTopLevelDeclInObjCContainer(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); D->FromASTFile = true; Index: test/Analysis/NoReturn.m =================================================================== --- test/Analysis/NoReturn.m +++ test/Analysis/NoReturn.m @@ -46,7 +46,7 @@ // Test cases. //===----------------------------------------------------------------------===// -int f1(int *x, NSString* s) { +int f1(const int *x, NSString* s) { if (x) ++x; @@ -55,7 +55,7 @@ return *x; // no-warning } -int f2(int *x, ...) { +int f2(const int *x, ...) { if (x) ++x; va_list alist; @@ -66,7 +66,7 @@ return *x; // no-warning } -int f3(int* x) { +int f3(const int* x) { if (x) ++x; @@ -79,7 +79,7 @@ @interface CustomException : NSException @end -int testCustomException(int *x) { +int testCustomException(const int *x) { if (x != 0) return 0; [CustomException raise:@"Blah" format:@"abc"]; Index: test/Analysis/bstring.c =================================================================== --- test/Analysis/bstring.c +++ test/Analysis/bstring.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s -// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -analyze -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -Wno-nonconst-parameter -verify %s //===----------------------------------------------------------------------=== // Declarations @@ -302,7 +302,7 @@ clang_analyzer_eval(result == a); // no-warning (above is fatal) } -void mempcpy_unknownable_size (char *src, float n) { +void mempcpy_unknownable_size (const char *src, float n) { char a[4]; // This used to crash because we don't model floats. mempcpy(a, src, (size_t)n); Index: test/Analysis/casts.c =================================================================== --- test/Analysis/casts.c +++ test/Analysis/casts.c @@ -54,7 +54,7 @@ // Test cast VariableSizeArray to pointer does not crash. void *memcpy(void *, void const *, unsigned long); typedef unsigned char Byte; -void doit(char *data, int len) { +void doit(const char *data, int len) { if (len) { Byte buf[len]; memcpy(buf, data, len); @@ -76,7 +76,7 @@ return 0; } -int foo (int* p) { +int foo (const int* p) { int y = 0; if (p == 0) { if ((*((void**)&p)) == (void*)0) // Test that the cast to void preserves the symbolic region. Index: test/Analysis/coverage.c =================================================================== --- test/Analysis/coverage.c +++ test/Analysis/coverage.c @@ -4,7 +4,7 @@ typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); -static int another_function(int *y) { +static int another_function(const int *y) { if (*y > 0) return *y; return 0; Index: test/Analysis/inlining/false-positive-suppression.c =================================================================== --- test/Analysis/inlining/false-positive-suppression.c +++ test/Analysis/inlining/false-positive-suppression.c @@ -222,7 +222,7 @@ #endif } -int derefArg(int *p) { +int derefArg(const int *p) { return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} @@ -233,7 +233,7 @@ derefArg(cond ? &x : getNull()); } -int derefArgCast(char *p) { +int derefArgCast(const char *p) { return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} @@ -244,7 +244,7 @@ derefArgCast((char*)((unsigned)cond ? &x : getNull())); } -int derefAssignment(int *p) { +int derefAssignment(const int *p) { return *p; #ifndef SUPPRESSED // expected-warning@-2 {{Dereference of null pointer}} Index: test/Analysis/inlining/inline-defensive-checks.c =================================================================== --- test/Analysis/inlining/inline-defensive-checks.c +++ test/Analysis/inlining/inline-defensive-checks.c @@ -1,18 +1,18 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s // Perform inline defensive checks. -void idc(int *p) { +void idc(const int *p) { if (p) ; } -int test01(int *p) { +int test01(const int *p) { if (p) ; return *p; // expected-warning {{Dereference of null pointer}} } -int test02(int *p, int *x) { +int test02(const int *p, const int *x) { if (p) ; idc(p); @@ -21,25 +21,25 @@ return *p; // expected-warning {{Dereference of null pointer}} } -int test03(int *p, int *x) { +int test03(const int *p, int *x) { idc(p); if (p) ; return *p; // False negative } -int deref04(int *p) { +int deref04(const int *p) { return *p; // expected-warning {{Dereference of null pointer}} } -int test04(int *p) { +int test04(const int *p) { if (p) ; idc(p); return deref04(p); } -int test11(int *q, int *x) { +int test11(int *q, const int *x) { int *p = q; if (q) ; @@ -60,7 +60,7 @@ return *p; } -int test21(int *q, int *x) { +int test21(int *q, const int *x) { if (q) ; if (x) @@ -69,7 +69,7 @@ return *p; // expected-warning{{Dereference of null pointer}} } -int test22(int *q, int *x) { +int test22(int *q, const int *x) { idc(q); if (x) ; @@ -77,7 +77,7 @@ return *p; } -int test23(int *q, int *x) { +int test23(int *q, const int *x) { idc(q); if (x) ; Index: test/Analysis/inlining/path-notes.m =================================================================== --- test/Analysis/inlining/path-notes.m +++ test/Analysis/inlining/path-notes.m @@ -136,7 +136,7 @@ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'x')}} } -void testNilReceiver(id *x) { +void testNilReceiver(const id *x) { if (*x) { // expected-note@-1 {{Taking false branch}} return; Index: test/Analysis/logical-ops.c =================================================================== --- test/Analysis/logical-ops.c +++ test/Analysis/logical-ops.c @@ -2,7 +2,7 @@ void clang_analyzer_eval(int); -void testAnd(int i, int *p) { +void testAnd(int i, const int *p) { int *nullP = 0; int *knownP = &i; clang_analyzer_eval((knownP && knownP) == 1); // expected-warning{{TRUE}} @@ -10,7 +10,7 @@ clang_analyzer_eval((knownP && p) == 1); // expected-warning{{UNKNOWN}} } -void testOr(int i, int *p) { +void testOr(int i, const int *p) { int *nullP = 0; int *knownP = &i; clang_analyzer_eval((nullP || knownP) == 1); // expected-warning{{TRUE}} @@ -27,7 +27,7 @@ } // These crashed the analyzer at some point. -int between(char *x) { +int between(const char *x) { extern char start[]; extern char end[]; return x >= start && x < end; Index: test/Analysis/malloc.c =================================================================== --- test/Analysis/malloc.c +++ test/Analysis/malloc.c @@ -961,7 +961,7 @@ } extern void exit(int) __attribute__ ((__noreturn__)); -void mallocExit(int *g) { +void mallocExit(const int *g) { struct xx *p = malloc(12); if (g != 0) exit(1); @@ -974,7 +974,7 @@ __attribute__ ((__noreturn__)); #define assert(expr) \ ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) -void mallocAssert(int *g) { +void mallocAssert(const int *g) { struct xx *p = malloc(12); assert(g != 0); @@ -1030,7 +1030,7 @@ } // expected-warning {{Potential memory leak}} // Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p. -void symbolLostWithStrcpy(char *s) { +void symbolLostWithStrcpy(const char *s) { char *p = malloc(12); p = strcpy(p, s); free(p); @@ -1044,7 +1044,7 @@ return __builtin___strcpy_chk (__dest, __src, __builtin_object_size (__dest, 2 > 1)); } -void symbolLostWithStrcpy_InlineStrcpyVersion(char *s) { +void symbolLostWithStrcpy_InlineStrcpyVersion(const char *s) { char *p = malloc(12); p = ((__builtin_object_size (p, 0) != (size_t) -1) ? __builtin___strcpy_chk (p, s, __builtin_object_size (p, 2 > 1)) : __inline_strcpy_chk (p, s)); free(p); @@ -1440,7 +1440,7 @@ } -char *testLeakWithinReturn(char *str) { +char *testLeakWithinReturn(const char *str) { return strdup(strdup(str)); // expected-warning{{leak}} } Index: test/Analysis/misc-ps-region-store.m =================================================================== --- test/Analysis/misc-ps-region-store.m +++ test/Analysis/misc-ps-region-store.m @@ -448,7 +448,7 @@ //===----------------------------------------------------------------------===// // Exercise creating ElementRegion with symbolic super region. //===----------------------------------------------------------------------===// -void element_region_with_symbolic_superregion(int* p) { +void element_region_with_symbolic_superregion(const int* p) { int *x; int a; if (p[0] == 1) Index: test/Analysis/misc-ps.c =================================================================== --- test/Analysis/misc-ps.c +++ test/Analysis/misc-ps.c @@ -21,39 +21,39 @@ } -int PR8962 (int *t) { +int PR8962 (const int *t) { // This should look through the __extension__ no-op. if (__extension__ (t)) return 0; return *t; // expected-warning {{null pointer}} } -int PR8962_b (int *t) { +int PR8962_b (const int *t) { // This should still ignore the nested casts // which aren't handled by a single IgnoreParens() if (((int)((int)t))) return 0; return *t; // expected-warning {{null pointer}} } -int PR8962_c (int *t) { +int PR8962_c (const int *t) { // If the last element in a StmtExpr was a ParenExpr, it's still live if (({ (t ? (_Bool)0 : (_Bool)1); })) return 0; return *t; // no-warning } -int PR8962_d (int *t) { +int PR8962_d (const int *t) { // If the last element in a StmtExpr is an __extension__, it's still live if (({ __extension__(t ? (_Bool)0 : (_Bool)1); })) return 0; return *t; // no-warning } -int PR8962_e (int *t) { +int PR8962_e (const int *t) { // Redundant casts can mess things up! // Environment used to skip through NoOp casts, but LiveVariables didn't! if (({ (t ? (int)(int)0L : (int)(int)1L); })) return 0; return *t; // no-warning } -int PR8962_f (int *t) { +int PR8962_f (const int *t) { // The StmtExpr isn't a block-level expression here, // the __extension__ is. But the value should be attached to the StmtExpr // anyway. Make sure the block-level check is /before/ IgnoreParens. Index: test/Analysis/misc-ps.m =================================================================== --- test/Analysis/misc-ps.m +++ test/Analysis/misc-ps.m @@ -261,7 +261,7 @@ // Check that the pointer-to-conts arguments do not get invalidated by Obj C // interfaces. radar://10595327 -int rdar_10595327(char *str) { +int rdar_10595327(const char *str) { char fl = str[0]; int *p = 0; NSString *s = [NSString stringWithUTF8String:str]; Index: test/Analysis/null-deref-ps.c =================================================================== --- test/Analysis/null-deref-ps.c +++ test/Analysis/null-deref-ps.c @@ -27,7 +27,7 @@ return p->x++; // expected-warning{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}} } -int f3(char* x) { +int f3(const char* x) { int i = 2; Index: test/Analysis/objc-boxing.m =================================================================== --- test/Analysis/objc-boxing.m +++ test/Analysis/objc-boxing.m @@ -39,7 +39,7 @@ return @(strdup("boxed dynamic string")); // expected-warning{{Potential memory leak}} } -id const_char_pointer(int *x) { +id const_char_pointer(const int *x) { if (x) return @(3); return @(*x); // expected-warning {{Dereference of null pointer (loaded from variable 'x')}} Index: test/Analysis/pr22954.c =================================================================== --- test/Analysis/pr22954.c +++ test/Analysis/pr22954.c @@ -549,7 +549,7 @@ char * s2; }; -int f263(int n, char * len) { +int f263(int n, const char * len) { struct xx x263 = {0}; x263.s2 = strdup("hello"); char input[] = {'a', 'b', 'c', 'd'}; Index: test/Analysis/ptr-arith.c =================================================================== --- test/Analysis/ptr-arith.c +++ test/Analysis/ptr-arith.c @@ -63,7 +63,7 @@ int d = q - p; // no-warning } -void null_operand(int *a) { +void null_operand(const int *a) { start: // LHS is a label, RHS is NULL clang_analyzer_eval(&&start != 0); // expected-warning{{TRUE}} @@ -155,7 +155,7 @@ clang_analyzer_eval(&a >= &b); // expected-warning{{UNKNOWN}} } -void symbolic_region(int *p) { +void symbolic_region(const int *p) { int a; clang_analyzer_eval(&a != p); // expected-warning{{TRUE}} @@ -163,12 +163,12 @@ clang_analyzer_eval(&a >= p); // expected-warning{{UNKNOWN}} } -void PR7527 (int *p) { +void PR7527 (const int *p) { if (((int) p) & 1) // not crash return; } -void use_symbols(int *lhs, int *rhs) { +void use_symbols(const int *lhs, const int *rhs) { clang_analyzer_eval(lhs < rhs); // expected-warning{{UNKNOWN}} if (lhs < rhs) return; @@ -180,7 +180,7 @@ clang_analyzer_eval((lhs - rhs) == 5); // expected-warning{{TRUE}} } -void equal_implies_zero(int *lhs, int *rhs) { +void equal_implies_zero(const int *lhs, const int *rhs) { clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}} if (lhs == rhs) { clang_analyzer_eval(lhs != rhs); // expected-warning{{FALSE}} @@ -192,7 +192,7 @@ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}} } -void zero_implies_equal(int *lhs, int *rhs) { +void zero_implies_equal(const int *lhs, const int *rhs) { clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}} if ((rhs - lhs) == 0) { clang_analyzer_eval(lhs != rhs); // expected-warning{{FALSE}} @@ -204,7 +204,7 @@ clang_analyzer_eval(lhs != rhs); // expected-warning{{TRUE}} } -void comparisons_imply_size(int *lhs, int *rhs) { +void comparisons_imply_size(const int *lhs, const int *rhs) { clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}} if (lhs > rhs) { @@ -226,7 +226,7 @@ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}} } -void size_implies_comparison(int *lhs, int *rhs) { +void size_implies_comparison(const int *lhs, const int *rhs) { clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}} if ((rhs - lhs) < 0) { @@ -252,7 +252,7 @@ // False positives //------------------------------- -void zero_implies_reversed_equal(int *lhs, int *rhs) { +void zero_implies_reversed_equal(const int *lhs, const int *rhs) { clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}} if ((rhs - lhs) == 0) { // FIXME: Should be FALSE. @@ -268,7 +268,7 @@ clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}} } -void canonical_equal(int *lhs, int *rhs) { +void canonical_equal(const int *lhs, const int *rhs) { clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}} if (lhs == rhs) { // FIXME: Should be TRUE. Index: test/Analysis/retain-release-inline.m =================================================================== --- test/Analysis/retain-release-inline.m +++ test/Analysis/retain-release-inline.m @@ -299,7 +299,7 @@ //===----------------------------------------------------------------------===// // On return (intraprocedural), assume CF objects are leaked. -CFStringRef test_return_ratained_CF(char *bytes) { +CFStringRef test_return_ratained_CF(const char *bytes) { CFStringRef str; return CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}} } @@ -325,7 +325,7 @@ return x; } -void test_test_return_inline(char *bytes) { +void test_test_return_inline(const char *bytes) { CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // After this call, 'str' really has +2 reference count. CFStringRef str2 = test_return_inline(str); @@ -335,7 +335,7 @@ CFRelease(str2); } -void test_test_return_inline_2(char *bytes) { +void test_test_return_inline_2(const char *bytes) { CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}} // After this call, 'str' really has +2 reference count. CFStringRef str2 = test_return_inline(str); Index: test/Analysis/retain-release.m =================================================================== --- test/Analysis/retain-release.m +++ test/Analysis/retain-release.m @@ -605,7 +605,7 @@ // int isFoo(char c); -static void rdar_6659160(char *inkind, char *inname) +static void rdar_6659160(const char *inkind, const char *inname) { // We currently expect that [NSObject alloc] cannot fail. This // will be a toggled flag in the future. It can indeed return null, but Index: test/Analysis/simple-stream-checks.c =================================================================== --- test/Analysis/simple-stream-checks.c +++ test/Analysis/simple-stream-checks.c @@ -2,7 +2,7 @@ #include "Inputs/system-header-simulator-for-simple-stream.h" -void checkDoubleFClose(int *Data) { +void checkDoubleFClose(const int *Data) { FILE *F = fopen("myfile.txt", "w"); if (F != 0) { fputs ("fopen example", F); @@ -14,7 +14,7 @@ } } -int checkLeak(int *Data) { +int checkLeak(const int *Data) { FILE *F = fopen("myfile.txt", "w"); if (F != 0) { fputs ("fopen example", F); @@ -26,7 +26,7 @@ return 0; } -void checkLeakFollowedByAssert(int *Data) { +void checkLeakFollowedByAssert(const int *Data) { FILE *F = fopen("myfile.txt", "w"); if (F != 0) { fputs ("fopen example", F); @@ -71,7 +71,7 @@ return; // no warning } -void SymbolDoesNotEscapeThoughStringAPIs(char *Data) { +void SymbolDoesNotEscapeThoughStringAPIs(const char *Data) { FILE *F = fopen("myfile.txt", "w"); fputc(*Data, F); return; // expected-warning {{Opened file is never closed; potential resource leak}} Index: test/Analysis/stack-addr-ps.c =================================================================== --- test/Analysis/stack-addr-ps.c +++ test/Analysis/stack-addr-ps.c @@ -38,7 +38,7 @@ return p; // expected-warning{{Address of stack memory}} } -int array_test(int x[2]) { +int array_test(const int x[2]) { return x[0]; // no-warning } Index: test/Analysis/string.c =================================================================== --- test/Analysis/string.c +++ test/Analysis/string.c @@ -221,11 +221,11 @@ return strnlen("abc", (int)f); } -void strnlen_is_not_strlen(char *x) { +void strnlen_is_not_strlen(const char *x) { clang_analyzer_eval(strnlen(x, 10) == strlen(x)); // expected-warning{{UNKNOWN}} } -void strnlen_at_limit(char *x) { +void strnlen_at_limit(const char *x) { size_t len = strnlen(x, 10); clang_analyzer_eval(len <= 10); // expected-warning{{TRUE}} clang_analyzer_eval(len == 10); // expected-warning{{UNKNOWN}} @@ -263,7 +263,7 @@ #endif /* VARIANT */ -void strcpy_null_dst(char *x) { +void strcpy_null_dst(const char *x) { strcpy(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}} } @@ -280,7 +280,7 @@ } extern int globalInt; -void strcpy_effects(char *x, char *y) { +void strcpy_effects(char *x, const char *y) { char a = x[0]; if (globalInt != 42) return; @@ -291,13 +291,13 @@ clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}} } -void strcpy_overflow(char *y) { +void strcpy_overflow(const char *y) { char x[4]; if (strlen(y) == 4) strcpy(x, y); // expected-warning{{String copy function overflows destination buffer}} } -void strcpy_no_overflow(char *y) { +void strcpy_no_overflow(const char *y) { char x[4]; if (strlen(y) == 3) strcpy(x, y); // no-warning @@ -322,7 +322,7 @@ #endif /* VARIANT */ -void stpcpy_effect(char *x, char *y) { +void stpcpy_effect(char *x, const char *y) { char a = x[0]; clang_analyzer_eval(stpcpy(x, y) == &x[strlen(y)]); // expected-warning{{TRUE}} @@ -330,13 +330,13 @@ clang_analyzer_eval(a == x[0]); // expected-warning{{UNKNOWN}} } -void stpcpy_overflow(char *y) { +void stpcpy_overflow(const char *y) { char x[4]; if (strlen(y) == 4) stpcpy(x, y); // expected-warning{{String copy function overflows destination buffer}} } -void stpcpy_no_overflow(char *y) { +void stpcpy_no_overflow(const char *y) { char x[4]; if (strlen(y) == 3) stpcpy(x, y); // no-warning @@ -361,7 +361,7 @@ #endif /* VARIANT */ -void strcat_null_dst(char *x) { +void strcat_null_dst(const char *x) { strcat(NULL, x); // expected-warning{{Null pointer argument in call to string copy function}} } @@ -373,7 +373,7 @@ strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcat_fn', which is not a null-terminated string}} } -void strcat_effects(char *y) { +void strcat_effects(const char *y) { char x[8] = "123"; size_t orig_len = strlen(x); char a = x[0]; @@ -385,25 +385,25 @@ clang_analyzer_eval((int)strlen(x) == (orig_len + strlen(y))); // expected-warning{{TRUE}} } -void strcat_overflow_0(char *y) { +void strcat_overflow_0(const char *y) { char x[4] = "12"; if (strlen(y) == 4) strcat(x, y); // expected-warning{{String copy function overflows destination buffer}} } -void strcat_overflow_1(char *y) { +void strcat_overflow_1(const char *y) { char x[4] = "12"; if (strlen(y) == 3) strcat(x, y); // expected-warning{{String copy function overflows destination buffer}} } -void strcat_overflow_2(char *y) { +void strcat_overflow_2(const char *y) { char x[4] = "12"; if (strlen(y) == 2) strcat(x, y); // expected-warning{{String copy function overflows destination buffer}} } -void strcat_no_overflow(char *y) { +void strcat_no_overflow(const char *y) { char x[5] = "12"; if (strlen(y) == 2) strcat(x, y); // no-warning @@ -429,7 +429,7 @@ // There is no strcat_unknown_dst_length because if we can't get a symbolic // length for the "before" strlen, we won't be able to set one for "after". -void strcat_too_big(char *dst, char *src) { +void strcat_too_big(char *dst, const char *src) { // We assume this can never actually happen, so we don't get a warning. if (strlen(dst) != (((size_t)0) - 2)) return; @@ -458,7 +458,7 @@ #endif /* VARIANT */ -void strncpy_null_dst(char *x) { +void strncpy_null_dst(const char *x) { strncpy(NULL, x, 5); // expected-warning{{Null pointer argument in call to string copy function}} } @@ -470,7 +470,7 @@ strncpy(x, (char*)&strcpy_fn, 5); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}} } -void strncpy_effects(char *x, char *y) { +void strncpy_effects(char *x, const char *y) { char a = x[0]; clang_analyzer_eval(strncpy(x, y, 5) == x); // expected-warning{{TRUE}} @@ -478,19 +478,19 @@ clang_analyzer_eval(a == x[0]); // expected-warning{{UNKNOWN}} } -void strncpy_overflow(char *y) { +void strncpy_overflow(const char *y) { char x[4]; if (strlen(y) == 4) strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}} } -void strncpy_no_overflow(char *y) { +void strncpy_no_overflow(const char *y) { char x[4]; if (strlen(y) == 3) strncpy(x, y, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}} } -void strncpy_no_overflow2(char *y, int n) { +void strncpy_no_overflow2(const char *y, int n) { if (n <= 4) return; @@ -499,19 +499,19 @@ strncpy(x, y, n); // expected-warning{{Size argument is greater than the length of the destination buffer}} } -void strncpy_truncate(char *y) { +void strncpy_truncate(const char *y) { char x[4]; if (strlen(y) == 4) strncpy(x, y, 3); // no-warning } -void strncpy_no_truncate(char *y) { +void strncpy_no_truncate(const char *y) { char x[4]; if (strlen(y) == 3) strncpy(x, y, 3); // no-warning } -void strncpy_exactly_matching_buffer(char *y) { +void strncpy_exactly_matching_buffer(const char *y) { char x[4]; strncpy(x, y, 4); // no-warning @@ -520,7 +520,7 @@ clang_analyzer_eval(strlen(x) > 4); // expected-warning{{UNKNOWN}} } -void strncpy_zero(char *src) { +void strncpy_zero(const char *src) { char dst[] = "123"; strncpy(dst, src, 0); // no-warning } @@ -550,7 +550,7 @@ #endif /* VARIANT */ -void strncat_null_dst(char *x) { +void strncat_null_dst(const char *x) { strncat(NULL, x, 4); // expected-warning{{Null pointer argument in call to string copy function}} } @@ -562,7 +562,7 @@ strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to string copy function is the address of the function 'strncat_fn', which is not a null-terminated string}} } -void strncat_effects(char *y) { +void strncat_effects(const char *y) { char x[8] = "123"; size_t orig_len = strlen(x); char a = x[0]; @@ -574,36 +574,36 @@ clang_analyzer_eval(strlen(x) == (orig_len + strlen(y))); // expected-warning{{TRUE}} } -void strncat_overflow_0(char *y) { +void strncat_overflow_0(const char *y) { char x[4] = "12"; if (strlen(y) == 4) strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} } -void strncat_overflow_1(char *y) { +void strncat_overflow_1(const char *y) { char x[4] = "12"; if (strlen(y) == 3) strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} } -void strncat_overflow_2(char *y) { +void strncat_overflow_2(const char *y) { char x[4] = "12"; if (strlen(y) == 2) strncat(x, y, strlen(y)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} } -void strncat_overflow_3(char *y) { +void strncat_overflow_3(const char *y) { char x[4] = "12"; if (strlen(y) == 4) strncat(x, y, 2); // expected-warning{{Size argument is greater than the free space in the destination buffer}} } -void strncat_no_overflow_1(char *y) { +void strncat_no_overflow_1(const char *y) { char x[5] = "12"; if (strlen(y) == 2) strncat(x, y, strlen(y)); // no-warning } -void strncat_no_overflow_2(char *y) { +void strncat_no_overflow_2(const char *y) { char x[4] = "12"; if (strlen(y) == 4) strncat(x, y, 1); // no-warning @@ -614,7 +614,7 @@ clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{TRUE}} } -void strncat_symbolic_src_length(char *src) { +void strncat_symbolic_src_length(const char *src) { char dst[8] = "1234"; strncat(dst, src, 3); clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{TRUE}} @@ -653,7 +653,7 @@ clang_analyzer_eval(strlen(dst) == 4); // expected-warning{{UNKNOWN}} } -void strncat_too_big(char *dst, char *src) { +void strncat_too_big(char *dst, const char *src) { // We assume this will never actually happen, so we don't get a warning. if (strlen(dst) != (((size_t)0) - 2)) return; @@ -662,7 +662,7 @@ strncat(dst, src, 2); } -void strncat_zero(char *src) { +void strncat_zero(const char *src) { char dst[] = "123"; strncat(dst, src, 0); // no-warning } @@ -752,7 +752,7 @@ clang_analyzer_eval(strcmp("\0z", "\0y") == 0); // expected-warning{{TRUE}} } -void strcmp_unknown_arg (char *unknown) { +void strcmp_unknown_arg (const char *unknown) { clang_analyzer_eval(strcmp(unknown, unknown) == 0); // expected-warning{{TRUE}} } @@ -1088,7 +1088,7 @@ // aggressive in marking the (length of) src symbol dead. The length of dst // depends on src. This could be explicitely specified in the checker or the // logic for handling MetadataSymbol in SymbolManager needs to change. -void strcat_symbolic_src_length(char *src) { +void strcat_symbolic_src_length(const char *src) { char dst[8] = "1234"; strcat(dst, src); clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{UNKNOWN}} @@ -1096,7 +1096,7 @@ // The analyzer_eval call below should evaluate to true. Most likely the same // issue as the test above. -void strncpy_exactly_matching_buffer2(char *y) { +void strncpy_exactly_matching_buffer2(const char *y) { if (strlen(y) >= 4) return; Index: test/Analysis/svalbuilder-logic.c =================================================================== --- test/Analysis/svalbuilder-logic.c +++ test/Analysis/svalbuilder-logic.c @@ -3,7 +3,7 @@ // Testing core functionality of the SValBuilder. -int SValBuilderLogicNoCrash(int *x) { +int SValBuilderLogicNoCrash(const int *x) { return 3 - (int)(x +3); } Index: test/Analysis/unix-fns.c =================================================================== --- test/Analysis/unix-fns.c +++ test/Analysis/unix-fns.c @@ -185,7 +185,7 @@ } // Test inlining of dispatch_sync. -void test_dispatch_sync(dispatch_queue_t queue, int *q) { +void test_dispatch_sync(dispatch_queue_t queue, const int *q) { int *p = 0; dispatch_sync(queue, ^(void){ if (q) { Index: test/CodeGen/builtins-arm-exclusive.c =================================================================== --- test/CodeGen/builtins-arm-exclusive.c +++ test/CodeGen/builtins-arm-exclusive.c @@ -1,6 +1,6 @@ // REQUIRES: arm-registered-target -// RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -O3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-ARM64 +// RUN: %clang_cc1 -Wall -Wno-nonconst-parameter -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -Wall -Wno-nonconst-parameter -Werror -triple arm64-apple-ios7.0 -O3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-ARM64 // Make sure the canonical use works before going into smaller details: int atomic_inc(int *addr) { @@ -32,7 +32,7 @@ char a, b; }; -int test_ldrex(char *addr, long long *addr64, float *addrfloat) { +int test_ldrex(const char *addr, const long long *addr64, const float *addrfloat) { // CHECK-LABEL: @test_ldrex // CHECK-ARM64-LABEL: @test_ldrex int sum = 0; @@ -116,7 +116,7 @@ return sum; } -int test_ldaex(char *addr, long long *addr64, float *addrfloat) { +int test_ldaex(const char *addr, const long long *addr64, const float *addrfloat) { // CHECK-LABEL: @test_ldaex // CHECK-ARM64-LABEL: @test_ldaex int sum = 0; Index: test/CodeGen/builtins-systemz.c =================================================================== --- test/CodeGen/builtins-systemz.c +++ test/CodeGen/builtins-systemz.c @@ -9,7 +9,7 @@ uint64_t g; struct __htm_tdb global_tdb; -void test_htm1(struct __htm_tdb *tdb, int reg, int *mem, uint64_t *mem64) { +void test_htm1(struct __htm_tdb *tdb, int reg, const int *mem, uint64_t *mem64) { // CHECK-LABEL: test_htm1 __builtin_tbegin ((void *)0); Index: test/FixIt/dereference-addressof.c =================================================================== --- test/FixIt/dereference-addressof.c +++ test/FixIt/dereference-addressof.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-nonconst-parameter %s // RUN: cp %s %t // RUN: not %clang_cc1 -fsyntax-only -fixit -x c %t -// RUN: %clang_cc1 -fsyntax-only -pedantic -x c %t +// RUN: %clang_cc1 -fsyntax-only -pedantic -Wno-nonconst-parameter -x c %t void ip(int *aPtr) {} // expected-note{{passing argument to parameter 'aPtr' here}} void i(int a) {} // expected-note{{passing argument to parameter 'a' here}} Index: test/Parser/MicrosoftExtensionsInlineAsm.c =================================================================== --- test/Parser/MicrosoftExtensionsInlineAsm.c +++ test/Parser/MicrosoftExtensionsInlineAsm.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -verify -fms-extensions %s // expected-no-diagnostics -void __forceinline InterlockedBitTestAndSet (long *Base, long Bit) +void __forceinline InterlockedBitTestAndSet (const long *Base, long Bit) { __asm { mov eax, Bit Index: test/Parser/attributes.c =================================================================== --- test/Parser/attributes.c +++ test/Parser/attributes.c @@ -64,7 +64,7 @@ -int testFundef1(int *a) __attribute__((nonnull(1))) { // \ +int testFundef1(const int *a) __attribute__((nonnull(1))) { // \ // expected-warning {{GCC does not allow 'nonnull' attribute in this position on a function definition}} return *a; } @@ -75,14 +75,14 @@ testFundef2(); } -int testFundef3(int *a) __attribute__((nonnull(1), // \ +int testFundef3(const int *a) __attribute__((nonnull(1), // \ // expected-warning {{GCC does not allow 'nonnull' attribute in this position on a function definition}} pure)) { // \ // expected-warning {{GCC does not allow 'pure' attribute in this position on a function definition}} return *a; } -int testFundef4(int *a) __attribute__((nonnull(1))) // \ +int testFundef4(const int *a) __attribute__((nonnull(1))) // \ // expected-warning {{GCC does not allow 'nonnull' attribute in this position on a function definition}} __attribute((pure)) { // \ // expected-warning {{GCC does not allow 'pure' attribute in this position on a function definition}} Index: test/Parser/declarators.c =================================================================== --- test/Parser/declarators.c +++ test/Parser/declarators.c @@ -19,7 +19,7 @@ struct str; -void test2(int *P, int A) { +void test2(const int *P, int A) { struct str; // Hard case for array decl, not Array[*]. Index: test/Parser/pointer-arithmetic.c =================================================================== --- test/Parser/pointer-arithmetic.c +++ test/Parser/pointer-arithmetic.c @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -int *test1(int *a) { return a + 1; } -int *test2(int *a) { return 1 + a; } -int *test3(int *a) { return a - 1; } -int test4(int *a, int *b) { return a - b; } +int *test1(int *a) { return a + 1; } +int *test2(int *a) { return 1 + a; } +int *test3(int *a) { return a - 1; } +int test4(const int *a, const int *b) { return a - b; } -int test5(int *a, int *b) { return a + b; } /* expected-error {{invalid operands}} */ -int *test6(int *a) { return 1 - a; } /* expected-error {{invalid operands}} */ +int test5(const int *a, const int *b) { return a + b; } /* expected-error {{invalid operands}} */ +int *test6(const int *a) { return 1 - a; } /* expected-error {{invalid operands}} */ Index: test/Sema/annotate.c =================================================================== --- test/Sema/annotate.c +++ test/Sema/annotate.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -void __attribute__((annotate("foo"))) foo(float *a) { +void __attribute__((annotate("foo"))) foo(const float *a) { __attribute__((annotate("bar"))) int x; __attribute__((annotate(1))) int y; // expected-error {{'annotate' attribute requires a string}} __attribute__((annotate("bar", 1))) int z; // expected-error {{'annotate' attribute takes one argument}} Index: test/Sema/arm-neon-types.c =================================================================== --- test/Sema/arm-neon-types.c +++ test/Sema/arm-neon-types.c @@ -28,7 +28,7 @@ } // Warn for incompatible pointer types used with vld/vst intrinsics. -int16x8_t test5(int *p) { +int16x8_t test5(const int *p) { return vld1q_s16(p); // expected-warning {{incompatible pointer types}} } void test6(float *p, int32x2_t v) { Index: test/Sema/atomic-ops.c =================================================================== --- test/Sema/atomic-ops.c +++ test/Sema/atomic-ops.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -triple=i686-linux-gnu -std=c11 +// RUN: %clang_cc1 %s -verify -ffreestanding -fsyntax-only -Wno-nonconst-parameter -triple=i686-linux-gnu -std=c11 // Basic parsing/Sema tests for __c11_atomic_* Index: test/Sema/builtin-assume-aligned.c =================================================================== --- test/Sema/builtin-assume-aligned.c +++ test/Sema/builtin-assume-aligned.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wno-nonconst-parameter -verify %s int test1(int *a) { a = __builtin_assume_aligned(a, 32, 0ull); Index: test/Sema/builtin-assume.c =================================================================== --- test/Sema/builtin-assume.c +++ test/Sema/builtin-assume.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -fsyntax-only -verify %s -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -fsyntax-only -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wno-nonconst-parameter -verify %s int nonconst(void); int isconst(void) __attribute__((const)); Index: test/Sema/builtins-arm-exclusive.c =================================================================== --- test/Sema/builtins-arm-exclusive.c +++ test/Sema/builtins-arm-exclusive.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple armv7 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple armv7 -fsyntax-only -Wno-nonconst-parameter -verify %s struct Simple { char a, b; Index: test/Sema/builtins-arm64-exclusive.c =================================================================== --- test/Sema/builtins-arm64-exclusive.c +++ test/Sema/builtins-arm64-exclusive.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -fsyntax-only -Wno-nonconst-parameter -verify %s struct Simple { char a, b; Index: test/Sema/builtins.c =================================================================== --- test/Sema/builtins.c +++ test/Sema/builtins.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wstrlcpy-strlcat-size -Wno-string-plus-int -triple=i686-apple-darwin9 +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -Wstrlcpy-strlcat-size -Wno-string-plus-int -Wno-nonconst-parameter -triple=i686-apple-darwin9 // This test needs to set the target because it uses __builtin_ia32_vec_ext_v4si int test1(float a, int b) { Index: test/Sema/builtins.cl =================================================================== --- test/Sema/builtins.cl +++ test/Sema/builtins.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic +// RUN: %clang_cc1 %s -fsyntax-only -Wno-nonconst-parameter -verify -pedantic // expected-no-diagnostics kernel void test(global float *out, global float *in, global int* in2) { Index: test/Sema/c89.c =================================================================== --- test/Sema/c89.c +++ test/Sema/c89.c @@ -64,7 +64,7 @@ void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 feature}} */ void test11 (int x[static 4]); /* expected-warning {{static array size is a C99 feature}} */ -void test12 (int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */ +void test12 (const int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */ int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} */ } Index: test/Sema/compare.c =================================================================== --- test/Sema/compare.c +++ test/Sema/compare.c @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare %s -Wno-unreachable-code -int test(char *C) { // nothing here should warn. +int test(const char *C) { // nothing here should warn. return C != ((void*)0); return C != (void*)0; return C != 0; - return C != 1; // expected-warning {{comparison between pointer and integer ('char *' and 'int')}} + return C != 1; // expected-warning {{comparison between pointer and integer ('const char *' and 'int')}} } int ints(long a, unsigned long b) { @@ -201,18 +201,18 @@ ; } -int equal(char *a, const char *b) { +int equal(const char *a, const char *b) { return a == b; } -int arrays(char (*a)[5], char(*b)[10], char(*c)[5]) { +int arrays(const char (*a)[5], const char(*b)[10], const char(*c)[5]) { int d = (a == c); return a == b; // expected-warning {{comparison of distinct pointer types}} } -int pointers(int *a) { - return a > 0; // expected-warning {{ordered comparison between pointer and zero ('int *' and 'int') is an extension}} - return a > 42; // expected-warning {{ordered comparison between pointer and integer ('int *' and 'int')}} +int pointers(const int *a) { + return a > 0; // expected-warning {{ordered comparison between pointer and zero ('const int *' and 'int') is an extension}} + return a > 42; // expected-warning {{ordered comparison between pointer and integer ('const int *' and 'int')}} return a > (void *)0; // expected-warning {{comparison of distinct pointer types}} } Index: test/Sema/crash-invalid-array.c =================================================================== --- test/Sema/crash-invalid-array.c +++ test/Sema/crash-invalid-array.c @@ -15,8 +15,8 @@ } // rdar://13705391 -void foo(int a[*][2]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}} -void foo1(int a[2][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}} -void foo2(int a[*][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}} -void foo3(int a[2][*][2]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}} -void foo4(int a[2][*][*]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}} +void foo(const int a[*][2]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}} +void foo1(const int a[2][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}} +void foo2(const int a[*][*]) {(void)a[0][1]; } // expected-error {{variable length array must be bound in function definition}} +void foo3(const int a[2][*][2]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}} +void foo4(const int a[2][*][*]) {(void)a[0][1][1]; } // expected-error {{variable length array must be bound in function definition}} Index: test/Sema/empty1.c =================================================================== --- test/Sema/empty1.c +++ test/Sema/empty1.c @@ -74,14 +74,14 @@ return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'struct A'}} } -int func_8(struct emp_1 (*x)[10], struct emp_1 (*y)[10]) { - return x - y; // expected-warning {{subtraction of pointers to type 'struct emp_1 [10]' of zero size has undefined behavior}} +int func_8(const struct emp_1 (*x)[10], const struct emp_1 (*y)[10]) { + return x - y; // expected-warning {{subtraction of pointers to type 'const struct emp_1 [10]' of zero size has undefined behavior}} } -int func_9(struct emp_1 (*x)[], struct emp_1 (*y)[]) { - return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'struct emp_1 []'}} +int func_9(const struct emp_1 (*x)[], const struct emp_1 (*y)[]) { + return x - y; // expected-error {{arithmetic on a pointer to an incomplete type 'const struct emp_1 []'}} } -int func_10(int (*x)[0], int (*y)[0]) { - return x - y; // expected-warning {{subtraction of pointers to type 'int [0]' of zero size has undefined behavior}} +int func_10(const int (*x)[0], const int (*y)[0]) { + return x - y; // expected-warning {{subtraction of pointers to type 'const int [0]' of zero size has undefined behavior}} } Index: test/Sema/exprs.c =================================================================== --- test/Sema/exprs.c +++ test/Sema/exprs.c @@ -66,7 +66,7 @@ } // rdar://6319320 -void test5(int *X, float *P) { +void test5(const int *X, const float *P) { (float*)X = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}} #define FOO ((float*) X) FOO = P; // expected-error {{assignment to cast is illegal, lvalue casts are not supported}} @@ -77,8 +77,8 @@ X(); // expected-error {{called object type 'int' is not a function or function pointer}} } -void test7(int *P, _Complex float Gamma) { - P = (P-42) + Gamma*4; // expected-error {{invalid operands to binary expression ('int *' and '_Complex float')}} +void test7(const int *P, _Complex float Gamma) { + P = (P-42) + Gamma*4; // expected-error {{invalid operands to binary expression ('const int *' and '_Complex float')}} } Index: test/Sema/function.c =================================================================== --- test/Sema/function.c +++ test/Sema/function.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic // PR1892, PR11354 -void f(double a[restrict][5]) { __typeof(a) x = 10; } // expected-warning {{(aka 'double (*restrict)[5]')}} +void f(const double a[restrict][5]) { __typeof(a) x = 10; } // expected-warning {{(aka 'const double (*restrict)[5]')}} int foo (__const char *__path); int foo(__const char *__restrict __file); Index: test/Sema/merge-decls.c =================================================================== --- test/Sema/merge-decls.c +++ test/Sema/merge-decls.c @@ -71,9 +71,9 @@ int v[sizeof(a) == 1 ? 1 : -1]; } -int test5_f(int (*)[10]); -int test5_f(int (*x)[]) { - return sizeof(*x); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}} +int test5_f(const int (*)[10]); +int test5_f(const int (*x)[]) { + return sizeof(*x); // expected-error {{invalid application of 'sizeof' to an incomplete type 'const int []'}} } void test6_f(int (*a)[11]); Index: test/Sema/ms-inline-asm.c =================================================================== --- test/Sema/ms-inline-asm.c +++ test/Sema/ms-inline-asm.c @@ -1,5 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fms-extensions -fasm-blocks -Wno-microsoft -Wunused-label -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fms-extensions -fasm-blocks -Wno-microsoft -Wunused-label -Wno-nonconst-parameter -verify -fsyntax-only void t1(void) { __asm __asm // expected-error {{__asm used with no assembly instructions}} Index: test/Sema/pointer-subtract-compat.c =================================================================== --- test/Sema/pointer-subtract-compat.c +++ test/Sema/pointer-subtract-compat.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic typedef const char rchar; -int a(char* a, rchar* b) { +int a(const char* a, rchar* b) { return a-b; } Index: test/Sema/transparent-union.c =================================================================== --- test/Sema/transparent-union.c +++ test/Sema/transparent-union.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wno-nonconst-parameter -verify %s typedef union { int *ip; float *fp; Index: test/Sema/typecheck-binop.c =================================================================== --- test/Sema/typecheck-binop.c +++ test/Sema/typecheck-binop.c @@ -2,7 +2,7 @@ */ struct incomplete; // expected-note{{forward declaration of 'struct incomplete'}} -int sub1(int *a, double *b) { +int sub1(const int *a, const double *b) { return a - b; /* expected-error{{not pointers to compatible types}} */ } @@ -18,7 +18,7 @@ return P-Q; /* expected-warning{{arithmetic on pointers to void is a GNU extension}} */ } -int sub5(void *P, int *Q) { +int sub5(void *P, const int *Q) { return P-Q; /* expected-error{{not pointers to compatible types}} */ } Index: test/Sema/typo-correction.c =================================================================== --- test/Sema/typo-correction.c +++ test/Sema/typo-correction.c @@ -41,7 +41,7 @@ // expected-error {{use of undeclared identifier '__v2di'}} } -void f(long *a, long b) { +void f(const long *a, long b) { __atomic_or_fetch(a, b, c); // expected-error {{use of undeclared identifier 'c'}} } Index: test/Sema/uninit-variables.c =================================================================== --- test/Sema/uninit-variables.c +++ test/Sema/uninit-variables.c @@ -486,7 +486,7 @@ return a; } -int compound_assign(int *arr, int n) { +int compound_assign(const int *arr, int n) { int sum; // expected-note {{initialize}} for (int i = 0; i < n; ++i) sum += arr[i]; // expected-warning {{variable 'sum' is uninitialized}} @@ -504,7 +504,7 @@ return x; } -int self_init_in_cond(int *p) { +int self_init_in_cond(const int *p) { int n = ((p && (0 || 1)) && (n = *p)) ? n : -1; // ok return n; } Index: test/Sema/unused-expr.c =================================================================== --- test/Sema/unused-expr.c +++ test/Sema/unused-expr.c @@ -4,7 +4,7 @@ double sqrt(double X); // implicitly const because of no -fmath-errno! -void bar(volatile int *VP, int *P, int A, +void bar(volatile const int *VP, const int *P, int A, _Complex double C, volatile _Complex double VC) { VP < P; // expected-warning {{relational comparison result unused}} Index: test/Sema/varargs-x86-64.c =================================================================== --- test/Sema/varargs-x86-64.c +++ test/Sema/varargs-x86-64.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-apple-darwin9 +// RUN: %clang_cc1 -fsyntax-only -Wno-nonconst-parameter -verify %s -triple x86_64-apple-darwin9 // rdar://6726818 void f1() { Index: test/Sema/warn-logical-not-compare.c =================================================================== --- test/Sema/warn-logical-not-compare.c +++ test/Sema/warn-logical-not-compare.c @@ -196,7 +196,7 @@ return ret; } -int compare_pointers(int* a, int* b) { +int compare_pointers(const int* a, const int* b) { int ret; ret = !!a == !!b; ret = !!a != !!b; Index: test/Sema/warn-nonconst-parameter.c =================================================================== --- test/Sema/warn-nonconst-parameter.c +++ test/Sema/warn-nonconst-parameter.c @@ -0,0 +1,195 @@ +// RUN: %clang_cc1 -fsyntax-only -Wnonconst-parameter -verify %s + +// Currently the -Wnonconst-parameter only warns about pointer arguments. +// +// It can be defined both that the data is const and that the pointer is const, +// the -Wnonconst-parameter only checks if the data can be const-specified. +// +// It does not warn about pointers to records or function pointers. + +// Some external function where first argument is nonconst and second is const. +char* strcpy1(char *dest, const char *src); +unsigned my_strcpy(char *buf, const char *s); +unsigned my_strlen(const char *buf); + + +int warn1(int *p) { // expected-warning {{parameter 'p' can be const}} + return *p; +} + +void warn2(int *first, int *last) { // expected-warning {{parameter 'last' can be const}} + *first = 0; + if (first < last) {} // <- last can be const +} + +void warn3(char *p) { // expected-warning {{parameter 'p' can be const}} + char buf[10]; + strcpy1(buf, p); +} + + +void assign1(int *p) { // expected-warning {{parameter 'p' can be const}} + const int *q; + q = p; +} + +void assign2(int *p) { // expected-warning {{parameter 'p' can be const}} + const int *q; + q = p + 1; +} + +void assign3(int *p) { + *p = 0; +} + +void assign4(char *p) { + p[0] = 0; +} + +void assign5(int *p) { + int *q; + q = p++; +} + +void assign6(char *p) { + char *a, *b; + a = b = p; +} + +void assign7(char *a, char *b) { + char *x; + x = (a ? a : b); +} + +void assign8(unsigned char *str, const unsigned int i) { + unsigned char *p; + for (p = str + i; *p; ) {} +} + +void assign9(int *buf) { + int i, *p; + for (i=0, p=buf; i<10; i++, p++) { + *p = 1; + } +} + +void assign10(int *p, int x) { + for (int *q = p+x-1; 0; q++); +} + + +void init1(int *p) { // expected-warning {{parameter 'p' can be const}} + const int *q = p; +} + +void init2(int *p) { // expected-warning {{parameter 'p' can be const}} + const int *q = p + 1; +} + +void init3(int *p) { + int *q = p; +} + +void init4(float *p) { + int *q = (int *)p; +} + +void init5(int *p) { + int *i = p ? p : 0; +} + +void init6(int *p) { + int *a[] = {p,p,0}; +} + + +int return1(int *p) { // expected-warning {{parameter 'p' can be const}} + return *p; +} + +const int *return2(int *p) { // expected-warning {{parameter 'p' can be const}} + return p; +} + +const int *return3(int *p) { // expected-warning {{parameter 'p' can be const}} + return p+1; +} + +const char *return4(char *p) { // expected-warning {{parameter 'p' can be const}} + return p ? p : ""; +} + +char *return5(char *s) { + return s; +} + +char *return6(char *s) { + return s+1; +} + +char *return7(char *a, char *b) { + return a ? a : b; +} + +char return8(int *p) { + return ++(*p); +} + + +void dontwarn1(int *p) { + ++(*p); +} + +int dontwarn2(_Atomic(int) *p) { + return *p; +} + + + +void callFunction1(char *p) { + strcpy1(p, "abc"); +} + +void callFunction2(char *p) { + strcpy1(&p[0], "abc"); +} + +void callFunction3(char *p) { + strcpy1(p+2, "abc"); +} + +char *callFunction4(char *p) { + return strcpy1(p, "abc"); +} + +unsigned callFunction5(char *buf) { + unsigned len = my_strlen(buf); + return len + my_strcpy(buf, "abc"); +} + +void f6(int **p); +void callFunction6(int *p) { f6(&p); } + +typedef union {void*v;} t; +void f7(t obj); +void callFunction7(int *p) { + f7((t){p}); +} + + +// Don't warn about nonconst function pointers that can be const. +void functionpointer(double f(double), int x) { + f(x); +} + +// Don't warn about nonconst record pointers that can be const. +struct XY { int x; int y; }; +int recordpointer(struct XY *xy) { + return xy->x; +} + +// avoid fp for const pointer array +void constPointerArray(const char *remapped[][2]) +{ + const char *name = remapped[0][0]; +} Index: test/Sema/warn-sizeof-arrayarg.c =================================================================== --- test/Sema/warn-sizeof-arrayarg.c +++ test/Sema/warn-sizeof-arrayarg.c @@ -4,17 +4,17 @@ typedef int trungl_int; -void f(int a[10], Arr arr) { // expected-note 4 {{declared here}} +void f(const int a[10], const Arr arr) { // expected-note 4 {{declared here}} /* Should warn. */ (void)sizeof(a); // \ - // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}} + // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const int [10]'}} (void)sizeof((((a)))); // \ - // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}} + // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const int [10]'}} (void)sizeof a; // \ - // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'int [10]'}} + // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const int [10]'}} (void)sizeof arr; // \ - // expected-warning{{sizeof on array function parameter will return size of 'int *' instead of 'Arr' (aka 'int [10]')}} + // expected-warning{{sizeof on array function parameter will return size of 'const int *' instead of 'const Arr' (aka 'int const[10]')}} /* Shouldn't warn. */ int b[10]; Index: test/Sema/warn-strncat-size.c =================================================================== --- test/Sema/warn-strncat-size.c +++ test/Sema/warn-strncat-size.c @@ -24,7 +24,7 @@ char s2[200]; int x; -void test(char *src) { +void test(const char *src) { char dest[10]; strncat(dest, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", sizeof(dest) - strlen(dest) - 1); // no-warning @@ -71,6 +71,6 @@ } // Non-array type gets a different error message. -void f(char* s, char* d) { +void f(const char* s, char* d) { strncat(d, s, sizeof(d)); // expected-warning {{the value of the size argument to 'strncat' is wrong}} } Index: test/Sema/warn-thread-safety-analysis.c =================================================================== --- test/Sema/warn-thread-safety-analysis.c +++ test/Sema/warn-thread-safety-analysis.c @@ -68,7 +68,7 @@ *a = value; } -int get_value(int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){ +int get_value(const int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){ return *p; } Index: test/Sema/warn-type-safety-mpi-hdf5.c =================================================================== --- test/Sema/warn-type-safety-mpi-hdf5.c +++ test/Sema/warn-type-safety-mpi-hdf5.c @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c99 -DMPICH -fsyntax-only -verify %s -// RUN: %clang_cc1 -x c++ -std=c++98 -DOPEN_MPI -fsyntax-only -verify %s -// RUN: %clang_cc1 -x c++ -std=c++98 -DMPICH -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fsyntax-only -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -std=c99 -DMPICH -fsyntax-only -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -x c++ -std=c++98 -DOPEN_MPI -fsyntax-only -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -x c++ -std=c++98 -DMPICH -fsyntax-only -Wno-nonconst-parameter -verify %s // -// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fno-signed-char -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c99 -DMPICH -fno-signed-char -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c99 -DOPEN_MPI -fno-signed-char -fsyntax-only -Wno-nonconst-parameter -verify %s +// RUN: %clang_cc1 -std=c99 -DMPICH -fno-signed-char -fsyntax-only -Wno-nonconst-parameter -verify %s //===--- limits.h mock ----------------------------------------------------===// Index: test/SemaObjC/nullability.m =================================================================== --- test/SemaObjC/nullability.m +++ test/SemaObjC/nullability.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -fblocks -Woverriding-method-mismatch -Wno-nullability-declspec %s -verify +// RUN: %clang_cc1 -fsyntax-only -fblocks -Woverriding-method-mismatch -Wno-nullability-declspec -Wno-nonconst-parameter %s -verify __attribute__((objc_root_class)) @interface NSFoo Index: test/SemaObjC/uninit-variables.m =================================================================== --- test/SemaObjC/uninit-variables.m +++ test/SemaObjC/uninit-variables.m @@ -36,7 +36,7 @@ } } -int test_abort_on_exceptions(int y, NSException *e, NSString *s, int *z, ...) { +int test_abort_on_exceptions(int y, NSException *e, NSString *s, const int *z, ...) { int x; // expected-note {{initialize the variable 'x' to silence this warning}} if (y == 1) { va_list alist; Index: test/SemaOpenCL/address-spaces.cl =================================================================== --- test/SemaOpenCL/address-spaces.cl +++ test/SemaOpenCL/address-spaces.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only +// RUN: %clang_cc1 %s -verify -pedantic -Wno-nonconst-parameter -fsyntax-only __constant int ci = 1; Index: test/SemaOpenCL/cond.cl =================================================================== --- test/SemaOpenCL/cond.cl +++ test/SemaOpenCL/cond.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only +// RUN: %clang_cc1 %s -verify -pedantic -Wno-nonconst-parameter -fsyntax-only typedef unsigned char uchar; typedef unsigned char uchar2 __attribute__((ext_vector_type(2))); Index: test/SemaOpenCL/event_t_overload.cl =================================================================== --- test/SemaOpenCL/event_t_overload.cl +++ test/SemaOpenCL/event_t_overload.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only +// RUN: %clang_cc1 %s -verify -pedantic -Wno-nonconst-parameter -fsyntax-only void __attribute__((overloadable)) foo(event_t, __local char *); // expected-note {{candidate function not viable: no known conversion from '__global int *' to '__local char *' for 2nd argument}} void __attribute__((overloadable)) foo(event_t, __local float *); // expected-note {{candidate function not viable: no known conversion from '__global int *' to '__local float *' for 2nd argument}}