diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/AST/ASTContext.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 4 | ||||
| -rw-r--r-- | clang/include/clang/AST/Type.h | 29 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 5 | ||||
| -rw-r--r-- | clang/include/clang/Parse/DeclSpec.h | 7 | ||||
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 42 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 29 | ||||
| -rw-r--r-- | clang/test/SemaCXX/function-type-qual.cpp | 23 | 
14 files changed, 139 insertions, 31 deletions
| diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b393e52c9c0..99ff107d8da 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -208,7 +208,8 @@ public:    /// getFunctionType - Return a normal function type with a typed argument    /// list.  isVariadic indicates whether the argument list includes '...'.    QualType getFunctionType(QualType ResultTy, const QualType *ArgArray, -                           unsigned NumArgs, bool isVariadic); +                           unsigned NumArgs, bool isVariadic, +                           unsigned TypeQuals = 0);    /// getTypeDeclType - Return the unique reference to the type for    /// the specified type declaration. diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 89d135e3696..af666022f4f 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -230,6 +230,10 @@ public:    /// Should only be called for instance methods.    QualType getThisType(ASTContext &C) const; +  unsigned getTypeQualifiers() const { +    return getType()->getAsFunctionTypeProto()->getTypeQuals(); +  } +    // Implement isa/cast/dyncast/etc.    static bool classof(const Decl *D) { return D->getKind() == CXXMethod; }    static bool classof(const CXXMethodDecl *D) { return true; } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 29941aad091..7915dd056f7 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -157,6 +157,10 @@ public:    QualType getWithAdditionalQualifiers(unsigned TQs) const {      return QualType(getTypePtr(), TQs|getCVRQualifiers());    } + +  QualType withConst() const { return getWithAdditionalQualifiers(Const); } +  QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);} +  QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);}    QualType getUnqualifiedType() const;    bool isMoreQualifiedThan(QualType Other) const; @@ -917,13 +921,25 @@ class FunctionType : public Type {    /// SubClassData - This field is owned by the subclass, put here to pack    /// tightly with the ivars in Type.    bool SubClassData : 1; + +  /// TypeQuals - Used only by FunctionTypeProto, put here to pack with the +  /// other bitfields. +  /// The qualifiers are part of FunctionTypeProto because... +  /// +  /// C++ 8.3.5p4: The return type, the parameter type list and the +  /// cv-qualifier-seq, [...], are part of the function type. +  /// +  unsigned TypeQuals : 3;    // The type returned by the function.    QualType ResultType;  protected: -  FunctionType(TypeClass tc, QualType res, bool SubclassInfo,QualType Canonical) -    : Type(tc, Canonical), SubClassData(SubclassInfo), ResultType(res) {} +  FunctionType(TypeClass tc, QualType res, bool SubclassInfo, +               unsigned typeQuals, QualType Canonical) +    : Type(tc, Canonical), +      SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}    bool getSubClassData() const { return SubClassData; } +  unsigned getTypeQuals() const { return TypeQuals; }  public:    QualType getResultType() const { return ResultType; } @@ -940,7 +956,7 @@ public:  /// no information available about its arguments.  class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode {    FunctionTypeNoProto(QualType Result, QualType Canonical) -    : FunctionType(FunctionNoProto, Result, false, Canonical) {} +    : FunctionType(FunctionNoProto, Result, false, 0, Canonical) {}    friend class ASTContext;  // ASTContext creates these.  public:    // No additional state past what FunctionType provides. @@ -970,8 +986,8 @@ protected:  /// arguments, not as having a single void argument.  class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode {    FunctionTypeProto(QualType Result, const QualType *ArgArray, unsigned numArgs, -                    bool isVariadic, QualType Canonical) -    : FunctionType(FunctionProto, Result, isVariadic, Canonical), +                    bool isVariadic, unsigned typeQuals, QualType Canonical) +    : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical),        NumArgs(numArgs) {      // Fill in the trailing argument array.      QualType *ArgInfo = reinterpret_cast<QualType *>(this+1);; @@ -996,6 +1012,7 @@ public:    }    bool isVariadic() const { return getSubClassData(); } +  unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }    typedef const QualType *arg_type_iterator;    arg_type_iterator arg_type_begin() const { @@ -1013,7 +1030,7 @@ public:    void Profile(llvm::FoldingSetNodeID &ID);    static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,                        arg_type_iterator ArgTys, unsigned NumArgs, -                      bool isVariadic); +                      bool isVariadic, unsigned TypeQuals);  protected:      virtual void EmitImpl(llvm::Serializer& S) const; diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 342378ecbf9..7255e6a483b 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -1041,6 +1041,11 @@ DIAG(err_invalid_this_use, ERROR,       "invalid use of 'this' outside of a nonstatic member function")  DIAG(err_invalid_member_use_in_static_method, ERROR,       "invalid use of member '%0' in static member function") +DIAG(err_invalid_qualified_function_type, ERROR, +     "type qualifier is not allowed on this function") +DIAG(err_invalid_qualified_typedef_function_type_use, ERROR, +     "a qualified function type cannot be used to declare a nonmember function " +     "or a static member function")  DIAG(err_invalid_non_static_member_use, ERROR,       "invalid use of nonstatic data member '%0'")  DIAG(err_invalid_incomplete_type_use, ERROR, diff --git a/clang/include/clang/Parse/DeclSpec.h b/clang/include/clang/Parse/DeclSpec.h index 22d75a61512..f1734d4148c 100644 --- a/clang/include/clang/Parse/DeclSpec.h +++ b/clang/include/clang/Parse/DeclSpec.h @@ -442,6 +442,10 @@ struct DeclaratorChunk {      /// with ',...)', this is true.      bool isVariadic : 1; +    /// The type qualifiers: const/volatile/restrict. +    /// The qualifier bitmask values are the same as in QualType.  +    unsigned TypeQuals : 3; +      /// NumArgs - This is the number of formal arguments provided for the      /// declarator.      unsigned NumArgs; @@ -528,12 +532,13 @@ struct DeclaratorChunk {    /// getFunction - Return a DeclaratorChunk for a function.    static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,                                       ParamInfo *ArgInfo, unsigned NumArgs, -                                     SourceLocation Loc) { +                                     unsigned TypeQuals, SourceLocation Loc) {      DeclaratorChunk I;      I.Kind             = Function;      I.Loc              = Loc;      I.Fun.hasPrototype = hasProto;      I.Fun.isVariadic   = isVariadic; +    I.Fun.TypeQuals    = TypeQuals;      I.Fun.NumArgs      = NumArgs;      I.Fun.ArgInfo      = 0; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 75c58880486..f8129969b7b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -884,11 +884,13 @@ QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) {  /// getFunctionType - Return a normal function type with a typed argument  /// list.  isVariadic indicates whether the argument list includes '...'.  QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, -                                     unsigned NumArgs, bool isVariadic) { +                                     unsigned NumArgs, bool isVariadic, +                                     unsigned TypeQuals) {    // Unique functions, to guarantee there is only one function of a particular    // structure.    llvm::FoldingSetNodeID ID; -  FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic); +  FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, +                             TypeQuals);    void *InsertPos = 0;    if (FunctionTypeProto *FTP =  @@ -925,7 +927,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,      (FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) +                                  NumArgs*sizeof(QualType));    new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic, -                              Canonical); +                              TypeQuals, Canonical);    Types.push_back(FTP);    FunctionTypeProtos.InsertNode(FTP, InsertPos);    return QualType(FTP, 0); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 8baf4196bf6..a62ebad3651 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -64,9 +64,8 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {    assert(isInstance() && "No 'this' for static methods!");    QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(                                              cast<CXXRecordDecl>(getParent()))); -  QualType ThisTy = C.getPointerType(ClassTy); -  ThisTy.addConst(); -  return ThisTy; +  ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); +  return C.getPointerType(ClassTy).withConst();  }  CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD, diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 5de44762c39..87b91ae2ea9 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -705,15 +705,18 @@ const char *BuiltinType::getName() const {  void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result,                                  arg_type_iterator ArgTys, -                                unsigned NumArgs, bool isVariadic) { +                                unsigned NumArgs, bool isVariadic, +                                unsigned TypeQuals) {    ID.AddPointer(Result.getAsOpaquePtr());    for (unsigned i = 0; i != NumArgs; ++i)      ID.AddPointer(ArgTys[i].getAsOpaquePtr());    ID.AddInteger(isVariadic); +  ID.AddInteger(TypeQuals);  }  void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { -  Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic()); +  Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), +          getTypeQuals());  }  void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 27133d683c9..6bcb90b8ae6 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1213,6 +1213,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D) {  ///         direct-declarator '(' identifier-list[opt] ')'  /// [GNU]   direct-declarator '(' parameter-forward-declarations  ///                    parameter-type-list[opt] ')' +/// [C++]   direct-declarator '(' parameter-declaration-clause ')' +///                    cv-qualifier-seq[opt] exception-specification[opt]  ///  void Parser::ParseDirectDeclarator(Declarator &D) {    // Parse the first direct-declarator seen. @@ -1371,6 +1373,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {  ///           '=' assignment-expression  /// [GNU]   declaration-specifiers abstract-declarator[opt] attributes  /// +/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]" +/// and "exception-specification[opt]"(TODO). +///  void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,                                       AttributeList *AttrList,                                       bool RequiresArg) { @@ -1383,20 +1388,29 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,        Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);        delete AttrList;      } -     + +    ConsumeParen();  // Eat the closing ')'. + +    // cv-qualifier-seq[opt]. +    DeclSpec DS; +    if (getLang().CPlusPlus) { +      ParseTypeQualifierListOpt(DS); +      // FIXME: Parse exception-specification[opt]. +    } +      // Remember that we parsed a function type, and remember the attributes.      // int() -> no prototype, no '...'. -    D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/ false, +    D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,                                                 /*variadic*/ false, -                                               /*arglist*/ 0, 0, LParenLoc)); -     -    ConsumeParen();  // Eat the closing ')'. +                                               /*arglist*/ 0, 0, +                                               DS.getTypeQualifiers(), +                                               LParenLoc));      return;    }     // Alternatively, this parameter list may be an identifier list form for a    // K&R-style function:  void foo(a,b,c) -  if (Tok.is(tok::identifier) && +  if (!getLang().CPlusPlus && Tok.is(tok::identifier) &&        // K&R identifier lists can't have typedefs as identifiers, per        // C99 6.7.5.3p11.        !Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { @@ -1508,13 +1522,21 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,    // Leave prototype scope.    ExitScope(); +  // If we have the closing ')', eat it. +  MatchRHSPunctuation(tok::r_paren, LParenLoc); + +  // cv-qualifier-seq[opt]. +  DeclSpec DS; +  if (getLang().CPlusPlus) { +    ParseTypeQualifierListOpt(DS); +    // FIXME: Parse exception-specification[opt]. +  } +    // Remember that we parsed a function type, and remember the attributes.    D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,                                               &ParamInfo[0], ParamInfo.size(), +                                             DS.getTypeQualifiers(),                                               LParenLoc)); -   -  // If we have the closing ')', eat it and we're done. -  MatchRHSPunctuation(tok::r_paren, LParenLoc);  }  /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator @@ -1581,7 +1603,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,    // has no prototype.    D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,                                               &ParamInfo[0], ParamInfo.size(), -                                             LParenLoc)); +                                             /*TypeQuals*/0, LParenLoc));    // If we have the closing ')', eat it and we're done.    MatchRHSPunctuation(tok::r_paren, LParenLoc); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index f6d7037ad12..7ab9d869c2d 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1116,7 +1116,7 @@ Parser::ExprResult Parser::ParseBlockLiteralExpression() {    } else {      // Otherwise, pretend we saw (void).      ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, -                                                       0, 0, CaretLoc)); +                                                       0, 0, 0, CaretLoc));    }    // Inform sema that we are starting a block. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4c36b09af80..c83c4def467 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1820,7 +1820,7 @@ ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,    Error = Error; // Silence warning.    assert(!Error && "Error setting up implicit decl!");    Declarator D(DS, Declarator::BlockContext); -  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, Loc)); +  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, 0, Loc));    D.SetIdentifier(&II, Loc);    // Insert this function into translation-unit scope. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9b1543f7901..6fd1c5cc2fd 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -402,7 +402,9 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,        if (FD->isInvalidDecl())          return true; -      return new DeclRefExpr(FD, FD->getType(), Loc); +      // FIXME: Handle 'mutable'. +      return new DeclRefExpr(FD, +        FD->getType().getWithAdditionalQualifiers(MD->getTypeQualifiers()),Loc);      }      return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName()); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a12ec3ad7c8..7bcd1e5765f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -409,7 +409,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {          if (getLangOptions().CPlusPlus) {            // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the            // function takes no arguments. -          T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic); +          T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals);          } else {            // Simple void foo(), where the incoming T is the result type.            T = Context.getFunctionTypeNoProto(T); @@ -482,7 +482,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {            ArgTys.push_back(ArgTy);          }          T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), -                                    FTI.isVariadic); +                                    FTI.isVariadic, FTI.TypeQuals);        }        break;      } @@ -491,6 +491,31 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {      if (const AttributeList *AL = DeclType.getAttrs())        ProcessTypeAttributeList(T, AL);    } + +  if (getLangOptions().CPlusPlus && T->isFunctionType()) { +    const FunctionTypeProto *FnTy = T->getAsFunctionTypeProto(); +    assert(FnTy && "Why oh why is there not a FunctionTypeProto here ?"); + +    // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type +    // for a nonstatic member function, the function type to which a pointer +    // to member refers, or the top-level function type of a function typedef +    // declaration. +    if (FnTy->getTypeQuals() != 0 && +        D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && +        (D.getContext() != Declarator::MemberContext || +         D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { + +      if (D.isFunctionDeclarator()) +        Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); +      else +        Diag(D.getIdentifierLoc(), +             diag::err_invalid_qualified_typedef_function_type_use); + +      // Strip the cv-quals from the type. +      T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), +                                  FnTy->getNumArgs(), FnTy->isVariadic()); +    } +  }    // If there were any type attributes applied to the decl itself (not the    // type, apply the type attribute to the type!) diff --git a/clang/test/SemaCXX/function-type-qual.cpp b/clang/test/SemaCXX/function-type-qual.cpp new file mode 100644 index 00000000000..fbd8702a962 --- /dev/null +++ b/clang/test/SemaCXX/function-type-qual.cpp @@ -0,0 +1,23 @@ +// RUN: clang -fsyntax-only -verify %s 
 +
 +void f() const; // expected-error {{type qualifier is not allowed on this function}}
 +
 +typedef void cfn() const; 
 +cfn f2; // expected-error {{a qualified function type cannot be used to declare a nonmember function or a static member function}}
 +
 +class C {
 +  void f() const;
 +  cfn f2;
 +  static void f3() const; // expected-error {{type qualifier is not allowed on this function}}
 +  static cfn f4; // expected-error {{a qualified function type cannot be used to declare a nonmember function or a static member function}}
 +
 +  void m1() {
 +    x = 0;
 +  }
 +
 +  void m2() const {
 +    x = 0; // expected-error {{read-only variable is not assignable}}
 +  }
 +
 +  int x;
 +};
 | 

