diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 89 | ||||
| -rw-r--r-- | clang/test/Sema/declspec.c | 7 | 
3 files changed, 93 insertions, 9 deletions
diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index a2371545c68..494eb59ddd3 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -662,6 +662,12 @@ DIAG(err_typecheck_illegal_vla, ERROR,       "variable length array declared outside of any function")  DIAG(err_typecheck_negative_array_size, ERROR,       "array size is negative") +DIAG(warn_typecheck_function_qualifiers, WARNING, +     "qualifier on function type '%0' has unspecified behavior") +DIAG(err_typecheck_invalid_restrict_not_pointer, ERROR, +     "restrict requires a pointer or reference ('%0' is invalid)") +DIAG(err_typecheck_invalid_restrict_invalid_pointee, ERROR, +     "restrict pointee must be an object or incomplete type ('%0' is invalid)")  DIAG(ext_typecheck_zero_array_size, EXTENSION,       "zero size arrays are an extension")  DIAG(err_at_least_one_initializer_needed_to_size_array, ERROR, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5874477de1a..a1cabcff64e 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -28,7 +28,9 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) {    switch (DS.getTypeSpecType()) {    default: return QualType(); // FIXME: Handle unimp cases! -  case DeclSpec::TST_void: return Context.VoidTy; +  case DeclSpec::TST_void: +    Result = Context.VoidTy; +    break;    case DeclSpec::TST_char:      if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)        Result = Context.CharTy; @@ -145,6 +147,57 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) {    if (AttributeList *AL = DS.getAttributes())      DS.SetAttributes(ProcessTypeAttributes(Result, AL)); +  // Apply const/volatile/restrict qualifiers to T. +  if (unsigned TypeQuals = DS.getTypeQualifiers()) { + +    // Enforce C99 6.7.3p2: "Types other than pointer types derived from object +    // or incomplete types shall not be restrict-qualified."  C++ also allows +    // restrict-qualified references. +    if (TypeQuals & QualType::Restrict) { +      QualType EltTy; +      if (const PointerType *PT = Result->getAsPointerType()) +        EltTy = PT->getPointeeType(); +      else if (const ReferenceType *RT = Result->getAsReferenceType()) +        EltTy = RT->getReferenceeType(); +      else { +        Diag(DS.getRestrictSpecLoc(), +             diag::err_typecheck_invalid_restrict_not_pointer, +             Result.getAsString(), DS.getSourceRange()); +      } + +      // If we have a pointer or reference, the pointee must have an object or +      // incomplete type. +      if (!EltTy.isNull() && !EltTy->isObjectType() && +          !EltTy->isIncompleteType()) { +        Diag(DS.getRestrictSpecLoc(), +             diag::err_typecheck_invalid_restrict_invalid_pointee, +             EltTy.getAsString(), DS.getSourceRange()); +        EltTy = QualType(); +      } +       +      if (EltTy.isNull()) // Invalid restrict: remove the restrict qualifier. +        TypeQuals &= ~QualType::Restrict; +    } +     +    // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification +    // of a function type includes any type qualifiers, the behavior is +    // undefined." +    if (Result->isFunctionType() && TypeQuals) { +      // Get some location to point at, either the C or V location. +      SourceLocation Loc; +      if (TypeQuals & QualType::Const) +        Loc = DS.getConstSpecLoc(); +      else { +        assert((TypeQuals & QualType::Volatile) && +               "Has CV quals but not C or V?"); +        Loc = DS.getVolatileSpecLoc(); +      } +      Diag(Loc, diag::warn_typecheck_function_qualifiers, +           Result.getAsString(), DS.getSourceRange()); +    } +     +    Result = Result.getQualifiedType(TypeQuals); +  }    return Result;  } @@ -158,9 +211,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {    QualType T = ConvertDeclSpecToType(D.getDeclSpec()); -  // Apply const/volatile/restrict qualifiers to T. -  T = T.getQualifiedType(D.getDeclSpec().getTypeQualifiers()); -      // Walk the DeclTypeInfo, building the recursive type as we go.  DeclTypeInfos    // are ordered from the identifier out, which is opposite of what we want :).    for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { @@ -170,12 +220,22 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {      case DeclaratorChunk::Pointer:        if (T->isReferenceType()) {          // C++ 8.3.2p4: There shall be no ... pointers to references ... -        Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference, +        Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference,               D.getIdentifier() ? D.getIdentifier()->getName() : "type name");          D.setInvalidType(true);          T = Context.IntTy;        } +      // Enforce C99 6.7.3p2: "Types other than pointer types derived from +      // object or incomplete types shall not be restrict-qualified." +      if ((DeclType.Ptr.TypeQuals & QualType::Restrict) && +          !T->isObjectType() && !T->isIncompleteType()) { +        Diag(DeclType.Loc, +             diag::err_typecheck_invalid_restrict_invalid_pointee, +             T.getAsString()); +        DeclType.Ptr.TypeQuals &= QualType::Restrict; +      }         +                // Apply the pointer typequals to the pointer object.        T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals); @@ -187,16 +247,27 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {      case DeclaratorChunk::Reference:        if (const ReferenceType *RT = T->getAsReferenceType()) {          // C++ 8.3.2p4: There shall be no references to references. -        Diag(D.getIdentifierLoc(), -             diag::err_illegal_decl_reference_to_reference, +        Diag(DeclType.Loc, diag::err_illegal_decl_reference_to_reference,               D.getIdentifier() ? D.getIdentifier()->getName() : "type name");          D.setInvalidType(true);          T = RT->getReferenceeType();        } +      // Enforce C99 6.7.3p2: "Types other than pointer types derived from +      // object or incomplete types shall not be restrict-qualified." +      if (DeclType.Ref.HasRestrict && +          !T->isObjectType() && !T->isIncompleteType()) { +        Diag(DeclType.Loc, +             diag::err_typecheck_invalid_restrict_invalid_pointee, +             T.getAsString()); +        DeclType.Ref.HasRestrict = false; +      }         +        T = Context.getReferenceType(T); -         -      // FIXME: Handle Ref.Restrict! + +      // Handle restrict on references. +      if (DeclType.Ref.HasRestrict) +        T.addRestrict();        // See if there are any attributes on the pointer that apply to it.        if (AttributeList *AL = DeclType.Ref.AttrList) diff --git a/clang/test/Sema/declspec.c b/clang/test/Sema/declspec.c index e262b343cbb..36e54b25a71 100644 --- a/clang/test/Sema/declspec.c +++ b/clang/test/Sema/declspec.c @@ -13,4 +13,11 @@ static void buggy(int *x) { } // expected-error {{function definition declared '                                // expected-error {{cannot combine with previous 'typedef' declaration specifier}} \                                // expected-error {{cannot combine with previous 'struct' declaration specifier}} +// Type qualifiers. +typedef int f(void);  +typedef f* fptr; +const f* v1;         // expected-warning {{qualifier on function type 'f' has unspecified behavior}} +__restrict__ f* v2;  // expected-error {{restrict requires a pointer or reference ('f' is invalid)}} +__restrict__ fptr v3; // expected-error {{estrict pointee must be an object or incomplete type ('f' is invalid)}} +f *__restrict__ v4;   // expected-error {{restrict pointee must be an object or incomplete type ('f' is invalid)}}  | 

