Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4053,6 +4053,10 @@ "restrict requires a pointer or reference">; def err_typecheck_invalid_restrict_invalid_pointee : Error< "pointer to function type %0 may not be 'restrict' qualified">; +def warn_restrict_without_effect : Warning< + "restrict-qualified %select{function return type|type in a cast expression}0 " + "has no effect">, + InGroup, DefaultIgnore; def ext_typecheck_zero_array_size : Extension< "zero size arrays are an extension">, InGroup; def err_typecheck_zero_array_size : Error< Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1186,6 +1186,7 @@ QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); + void EmitDeclaredAtNotesForRestrict(QualType UT); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -7958,6 +7958,21 @@ } } + // If the return type is restrict qualified, warn the user. We only generate + // the warning here when the type is restrict qualified, but not locally so + // (qualified via a typedef, for example), because the local case is handled + // earlier (in diagnoseRedundantReturnTypeQualifiers). + if (const FunctionType *OrigNewType = dyn_cast(NewFD->getType())) { + QualType RT = OrigNewType->getReturnType(); + if (RT.isRestrictQualified() && !RT.isLocalRestrictQualified()) { + Diag(NewFD->getReturnTypeSourceRange().getBegin(), + diag::warn_restrict_without_effect) << 0 + << NewFD->getReturnTypeSourceRange(); + + EmitDeclaredAtNotesForRestrict(RT); + } + } + if (getLangOpts().CPlusPlus) { // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast(NewFD)) { Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3372,6 +3372,23 @@ } } +void Sema::EmitDeclaredAtNotesForRestrict(QualType UT) { + // It is often the case that restrict has been added via a typedef, and + // perhaps via a chain of typedefs. Help the user figure out where the + // restrict was added, if possible. + while (const TypedefType *TT = UT->getAs()) { + if (TT->getDecl()->getLocation().isValid()) + Diag(TT->getDecl()->getLocation(), diag::note_entity_declared_at) + << TT->getDecl(); + else + break; + + UT = TT->getDecl()->getUnderlyingType(); + if (!UT.isRestrictQualified()) + break; + } +} + TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { TypeProcessingState state(*this, D); @@ -3386,7 +3403,22 @@ transferARCOwnership(state, declSpecTy, ownership); } - return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); + TypeSourceInfo *CastTInfo = + GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); + + // If the cast type is restrict qualified, warn the user. Casting to a + // restrict type has no effect. We generate the diagnostic here because + // we have access to the Declarator source range (which will include the + // restrict qualifier when present locally). + QualType CastType = CastTInfo->getType(); + if (CastType.isRestrictQualified() && !FromTy.isRestrictQualified()) { + Diag(D.getLocStart(), diag::warn_restrict_without_effect) << 1 + << D.getSourceRange(); + + EmitDeclaredAtNotesForRestrict(CastType); + } + + return CastTInfo; } /// Map an AttributedType::Kind to an AttributeList::Kind. Index: test/Sema/restrict.c =================================================================== --- /dev/null +++ test/Sema/restrict.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -fsyntax-only -Wignored-qualifiers -verify + +// expected-warning@+1 {{'restrict' type qualifier on return type has no effect}} +int * restrict fooa(void); + +// expected-warning@+1 {{'restrict' type qualifier on return type has no effect}} +int * restrict foo(void) { + extern int i, *p, *q, *r; + + // expected-warning@+1 {{restrict-qualified type in a cast expression has no effect}} + r = (int * restrict)q; + + for (i=0; i < 1600; i++) + *(int * restrict)p++ = r[i]; + // expected-warning@-1 {{restrict-qualified type in a cast expression has no effect}} + + return p; +} + +typedef int * restrict intp; // expected-note {{declared here}} +// expected-warning@+1 {{restrict-qualified function return type has no effect}} +intp foob(void); + +typedef float * restrict floatp; // expected-note {{declared here}} +typedef floatp realp; // expected-note {{declared here}} +// expected-warning@+1 {{restrict-qualified function return type has no effect}} +realp fooc(void); + Index: test/SemaCXX/restrict.cpp =================================================================== --- /dev/null +++ test/SemaCXX/restrict.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -Wignored-qualifiers -verify + +// expected-warning@+3 {{restrict-qualified function return type has no effect}} +// expected-warning@+2 {{restrict-qualified function return type has no effect}} +template +T foo() { return T(0); } + +void goo() { +// expected-note@+1 {{in instantiation of function template specialization}} + foo(); +} + +typedef int * __restrict intp; +void hoo() { +// expected-note@+1 {{in instantiation of function template specialization}} + foo(); +} +