From: Argyrios Kyrtzidis Date: Fri, 24 Oct 2008 21:46:40 +0000 (+0000) Subject: -Add support for cv-qualifiers after function declarators. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=971c4fae6092976338b755af1d47dac07c8f16e3;p=clang -Add support for cv-qualifiers after function declarators. -Add withConst/withVolatile/withRestrict methods to QualType class, that return the QualType plus the respective qualifier. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58120 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index b393e52c9c..99ff107d8d 100644 --- a/include/clang/AST/ASTContext.h +++ b/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/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 89d135e369..af666022f4 100644 --- a/include/clang/AST/DeclCXX.h +++ b/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/include/clang/AST/Type.h b/include/clang/AST/Type.h index 29941aad09..7915dd056f 100644 --- a/include/clang/AST/Type.h +++ b/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(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/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 342378ecbf..7255e6a483 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/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/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 22d75a6151..f1734d4148 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/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/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 75c5888048..f8129969b7 100644 --- a/lib/AST/ASTContext.cpp +++ b/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/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 8baf4196bf..a62ebad365 100644 --- a/lib/AST/DeclCXX.cpp +++ b/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( cast(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/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5de44762c3..87b91ae2ea 100644 --- a/lib/AST/Type.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 27133d683c..6bcb90b8ae 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index f6d7037ad1..7ab9d869c2 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4c36b09af8..c83c4def46 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9b1543f790..6fd1c5cc2f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index a12ec3ad7c..7bcd1e5765 100644 --- a/lib/Sema/SemaType.cpp +++ b/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/test/SemaCXX/function-type-qual.cpp b/test/SemaCXX/function-type-qual.cpp new file mode 100644 index 0000000000..fbd8702a96 --- /dev/null +++ b/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; +};