Hi rsmith, dberlin, aaron.ballman,

We already include the restrict qualifier in the -Wignored-qualifiers checks, 
and so we'll produce a warning when -Wignored-qualifiers is in effect for a 
function declared with a restrict-qualified return type:

  warning: 'restrict' type qualifier on return type has no effect 
[-Wignored-qualifiers]
     int * restrict f8a(void);
           ^~~~~~~~~

but we don't warn about restrict-qualified types being used a return types 
generally. We also don't warn about restrict-qualified types in case 
expressions (which also don't convey any pointer-aliasing information because 
of how restrict's semantics are defined).

restrict's semantics are subtle, and there is a lot of misunderstanding about 
exactly how restrict can be used. Users often believe they can put restrict on 
function return types and in cast expressions to express pointer-aliasing 
information, and they can't (although the resulting code is legal).

This patch does two things. First, it adds a warning about 
indirectly-restrict-qualified function return types. For example, the code:

  typedef float * restrict floatp;
  typedef floatp realp;
  realp f8c(void);

will yield (when compiling with -Wignored-qualifiers):

  warning: restrict-qualified function return type has no effect 
[-Wignored-qualifiers]
  realp f8c(void);
  ^~~~~
  note: 'realp' declared here
  typedef floatp realp;
               ^
  note: 'floatp' declared here
  typedef float * restrict floatp;
                         ^

(the patch adds code that tries to look back through a chain of typedefs to 
find where the restrict was introduced, and then produces a corresponding 
series of notes, hopefully making it easy for the user to see where the 
restrict is coming from).

Second, we add a corresponding warning for restrict in case expressions, like 
this:

  extern int *r, *q;
  r = (int * restrict)q;

  for(i=0; i<100; i++)
    *(int * restrict)p++ =   r[i];

will yield:

  warning: restrict-qualified type in a cast expression has no effect 
[-Wignored-qualifiers]
         r = (int * restrict)q;
              ^~~~~~~~~~~~~~

  warning: restrict-qualified type in a cast expression has no effect 
[-Wignored-qualifiers]
             *(int * restrict)p++ =   r[i];
               ^~~~~~~~~~~~~~

One remaining problem (and I'm not sure how to best solve this), the cast 
warning should not fire when the cast is the top-level expression on the RHS of 
an assignment, and the cast is making the assignment legal. Suggestions here 
would be greatly appreciated.

Thanks again!

http://reviews.llvm.org/D5872

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaType.cpp
  test/Sema/restrict.c
  test/SemaCXX/restrict.cpp
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<IgnoredQualifiers>, DefaultIgnore;
 def ext_typecheck_zero_array_size : Extension<
   "zero size arrays are an extension">, InGroup<ZeroLengthArray>;
 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<FunctionType>(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<CXXConstructorDecl>(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<TypedefType>()) {
+    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 <typename T>
+T foo() { return T(0); }
+
+void goo() {
+// expected-note@+1 {{in instantiation of function template specialization}}
+  foo<float * __restrict>();
+}
+
+typedef int * __restrict intp;
+void hoo() {
+// expected-note@+1 {{in instantiation of function template specialization}}
+  foo<intp>();
+}
+
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to