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