-Add support for cv-qualifiers after function declarators.

-Add withConst/withVolatile/withRestrict methods to QualType class, that return the QualType plus the respective qualifier.

llvm-svn: 58120
This commit is contained in:
Argyrios Kyrtzidis 2008-10-24 21:46:40 +00:00
parent c157586598
commit 22c40fa285
14 changed files with 139 additions and 31 deletions

View File

@ -208,7 +208,8 @@ public:
/// getFunctionType - Return a normal function type with a typed argument /// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'. /// list. isVariadic indicates whether the argument list includes '...'.
QualType getFunctionType(QualType ResultTy, const QualType *ArgArray, 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 /// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration. /// the specified type declaration.

View File

@ -230,6 +230,10 @@ public:
/// Should only be called for instance methods. /// Should only be called for instance methods.
QualType getThisType(ASTContext &C) const; QualType getThisType(ASTContext &C) const;
unsigned getTypeQualifiers() const {
return getType()->getAsFunctionTypeProto()->getTypeQuals();
}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == CXXMethod; } static bool classof(const Decl *D) { return D->getKind() == CXXMethod; }
static bool classof(const CXXMethodDecl *D) { return true; } static bool classof(const CXXMethodDecl *D) { return true; }

View File

@ -158,6 +158,10 @@ public:
return QualType(getTypePtr(), TQs|getCVRQualifiers()); 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; QualType getUnqualifiedType() const;
bool isMoreQualifiedThan(QualType Other) const; bool isMoreQualifiedThan(QualType Other) const;
bool isAtLeastAsQualifiedAs(QualType Other) const; bool isAtLeastAsQualifiedAs(QualType Other) const;
@ -918,12 +922,24 @@ class FunctionType : public Type {
/// tightly with the ivars in Type. /// tightly with the ivars in Type.
bool SubClassData : 1; 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. // The type returned by the function.
QualType ResultType; QualType ResultType;
protected: protected:
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,QualType Canonical) FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
: Type(tc, Canonical), SubClassData(SubclassInfo), ResultType(res) {} unsigned typeQuals, QualType Canonical)
: Type(tc, Canonical),
SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}
bool getSubClassData() const { return SubClassData; } bool getSubClassData() const { return SubClassData; }
unsigned getTypeQuals() const { return TypeQuals; }
public: public:
QualType getResultType() const { return ResultType; } QualType getResultType() const { return ResultType; }
@ -940,7 +956,7 @@ public:
/// no information available about its arguments. /// no information available about its arguments.
class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode { class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode {
FunctionTypeNoProto(QualType Result, QualType Canonical) FunctionTypeNoProto(QualType Result, QualType Canonical)
: FunctionType(FunctionNoProto, Result, false, Canonical) {} : FunctionType(FunctionNoProto, Result, false, 0, Canonical) {}
friend class ASTContext; // ASTContext creates these. friend class ASTContext; // ASTContext creates these.
public: public:
// No additional state past what FunctionType provides. // No additional state past what FunctionType provides.
@ -970,8 +986,8 @@ protected:
/// arguments, not as having a single void argument. /// arguments, not as having a single void argument.
class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode { class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode {
FunctionTypeProto(QualType Result, const QualType *ArgArray, unsigned numArgs, FunctionTypeProto(QualType Result, const QualType *ArgArray, unsigned numArgs,
bool isVariadic, QualType Canonical) bool isVariadic, unsigned typeQuals, QualType Canonical)
: FunctionType(FunctionProto, Result, isVariadic, Canonical), : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical),
NumArgs(numArgs) { NumArgs(numArgs) {
// Fill in the trailing argument array. // Fill in the trailing argument array.
QualType *ArgInfo = reinterpret_cast<QualType *>(this+1);; QualType *ArgInfo = reinterpret_cast<QualType *>(this+1);;
@ -996,6 +1012,7 @@ public:
} }
bool isVariadic() const { return getSubClassData(); } bool isVariadic() const { return getSubClassData(); }
unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
typedef const QualType *arg_type_iterator; typedef const QualType *arg_type_iterator;
arg_type_iterator arg_type_begin() const { arg_type_iterator arg_type_begin() const {
@ -1013,7 +1030,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID); void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, unsigned NumArgs, arg_type_iterator ArgTys, unsigned NumArgs,
bool isVariadic); bool isVariadic, unsigned TypeQuals);
protected: protected:
virtual void EmitImpl(llvm::Serializer& S) const; virtual void EmitImpl(llvm::Serializer& S) const;

View File

@ -1041,6 +1041,11 @@ DIAG(err_invalid_this_use, ERROR,
"invalid use of 'this' outside of a nonstatic member function") "invalid use of 'this' outside of a nonstatic member function")
DIAG(err_invalid_member_use_in_static_method, ERROR, DIAG(err_invalid_member_use_in_static_method, ERROR,
"invalid use of member '%0' in static member function") "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, DIAG(err_invalid_non_static_member_use, ERROR,
"invalid use of nonstatic data member '%0'") "invalid use of nonstatic data member '%0'")
DIAG(err_invalid_incomplete_type_use, ERROR, DIAG(err_invalid_incomplete_type_use, ERROR,

View File

@ -442,6 +442,10 @@ struct DeclaratorChunk {
/// with ',...)', this is true. /// with ',...)', this is true.
bool isVariadic : 1; 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 /// NumArgs - This is the number of formal arguments provided for the
/// declarator. /// declarator.
unsigned NumArgs; unsigned NumArgs;
@ -528,12 +532,13 @@ struct DeclaratorChunk {
/// getFunction - Return a DeclaratorChunk for a function. /// getFunction - Return a DeclaratorChunk for a function.
static DeclaratorChunk getFunction(bool hasProto, bool isVariadic, static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
ParamInfo *ArgInfo, unsigned NumArgs, ParamInfo *ArgInfo, unsigned NumArgs,
SourceLocation Loc) { unsigned TypeQuals, SourceLocation Loc) {
DeclaratorChunk I; DeclaratorChunk I;
I.Kind = Function; I.Kind = Function;
I.Loc = Loc; I.Loc = Loc;
I.Fun.hasPrototype = hasProto; I.Fun.hasPrototype = hasProto;
I.Fun.isVariadic = isVariadic; I.Fun.isVariadic = isVariadic;
I.Fun.TypeQuals = TypeQuals;
I.Fun.NumArgs = NumArgs; I.Fun.NumArgs = NumArgs;
I.Fun.ArgInfo = 0; I.Fun.ArgInfo = 0;

View File

@ -884,11 +884,13 @@ QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) {
/// getFunctionType - Return a normal function type with a typed argument /// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'. /// list. isVariadic indicates whether the argument list includes '...'.
QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, 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 // Unique functions, to guarantee there is only one function of a particular
// structure. // structure.
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic); FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals);
void *InsertPos = 0; void *InsertPos = 0;
if (FunctionTypeProto *FTP = if (FunctionTypeProto *FTP =
@ -925,7 +927,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
(FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) + (FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) +
NumArgs*sizeof(QualType)); NumArgs*sizeof(QualType));
new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic, new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic,
Canonical); TypeQuals, Canonical);
Types.push_back(FTP); Types.push_back(FTP);
FunctionTypeProtos.InsertNode(FTP, InsertPos); FunctionTypeProtos.InsertNode(FTP, InsertPos);
return QualType(FTP, 0); return QualType(FTP, 0);

View File

@ -64,9 +64,8 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
assert(isInstance() && "No 'this' for static methods!"); assert(isInstance() && "No 'this' for static methods!");
QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>( QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(
cast<CXXRecordDecl>(getParent()))); cast<CXXRecordDecl>(getParent())));
QualType ThisTy = C.getPointerType(ClassTy); ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers());
ThisTy.addConst(); return C.getPointerType(ClassTy).withConst();
return ThisTy;
} }
CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD, CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,

View File

@ -705,15 +705,18 @@ const char *BuiltinType::getName() const {
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result, void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, arg_type_iterator ArgTys,
unsigned NumArgs, bool isVariadic) { unsigned NumArgs, bool isVariadic,
unsigned TypeQuals) {
ID.AddPointer(Result.getAsOpaquePtr()); ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i) for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr()); ID.AddPointer(ArgTys[i].getAsOpaquePtr());
ID.AddInteger(isVariadic); ID.AddInteger(isVariadic);
ID.AddInteger(TypeQuals);
} }
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { 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, void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,

View File

@ -1213,6 +1213,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D) {
/// direct-declarator '(' identifier-list[opt] ')' /// direct-declarator '(' identifier-list[opt] ')'
/// [GNU] direct-declarator '(' parameter-forward-declarations /// [GNU] direct-declarator '(' parameter-forward-declarations
/// parameter-type-list[opt] ')' /// parameter-type-list[opt] ')'
/// [C++] direct-declarator '(' parameter-declaration-clause ')'
/// cv-qualifier-seq[opt] exception-specification[opt]
/// ///
void Parser::ParseDirectDeclarator(Declarator &D) { void Parser::ParseDirectDeclarator(Declarator &D) {
// Parse the first direct-declarator seen. // Parse the first direct-declarator seen.
@ -1371,6 +1373,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// '=' assignment-expression /// '=' assignment-expression
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// [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, void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
AttributeList *AttrList, AttributeList *AttrList,
bool RequiresArg) { bool RequiresArg) {
@ -1384,19 +1389,28 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
delete AttrList; 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. // Remember that we parsed a function type, and remember the attributes.
// int() -> no prototype, no '...'. // int() -> no prototype, no '...'.
D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/ false, D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
/*variadic*/ false, /*variadic*/ false,
/*arglist*/ 0, 0, LParenLoc)); /*arglist*/ 0, 0,
DS.getTypeQualifiers(),
ConsumeParen(); // Eat the closing ')'. LParenLoc));
return; return;
} }
// Alternatively, this parameter list may be an identifier list form for a // Alternatively, this parameter list may be an identifier list form for a
// K&R-style function: void foo(a,b,c) // 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 // K&R identifier lists can't have typedefs as identifiers, per
// C99 6.7.5.3p11. // C99 6.7.5.3p11.
!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { !Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
@ -1508,13 +1522,21 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// Leave prototype scope. // Leave prototype scope.
ExitScope(); 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. // Remember that we parsed a function type, and remember the attributes.
D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
&ParamInfo[0], ParamInfo.size(), &ParamInfo[0], ParamInfo.size(),
DS.getTypeQualifiers(),
LParenLoc)); LParenLoc));
// If we have the closing ')', eat it and we're done.
MatchRHSPunctuation(tok::r_paren, LParenLoc);
} }
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
@ -1581,7 +1603,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
// has no prototype. // has no prototype.
D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false, D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
&ParamInfo[0], ParamInfo.size(), &ParamInfo[0], ParamInfo.size(),
LParenLoc)); /*TypeQuals*/0, LParenLoc));
// If we have the closing ')', eat it and we're done. // If we have the closing ')', eat it and we're done.
MatchRHSPunctuation(tok::r_paren, LParenLoc); MatchRHSPunctuation(tok::r_paren, LParenLoc);

View File

@ -1116,7 +1116,7 @@ Parser::ExprResult Parser::ParseBlockLiteralExpression() {
} else { } else {
// Otherwise, pretend we saw (void). // Otherwise, pretend we saw (void).
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
0, 0, CaretLoc)); 0, 0, 0, CaretLoc));
} }
// Inform sema that we are starting a block. // Inform sema that we are starting a block.

View File

@ -1820,7 +1820,7 @@ ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
Error = Error; // Silence warning. Error = Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!"); assert(!Error && "Error setting up implicit decl!");
Declarator D(DS, Declarator::BlockContext); 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); D.SetIdentifier(&II, Loc);
// Insert this function into translation-unit scope. // Insert this function into translation-unit scope.

View File

@ -402,7 +402,9 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
if (FD->isInvalidDecl()) if (FD->isInvalidDecl())
return true; 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()); return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName());

View File

@ -409,7 +409,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
if (getLangOptions().CPlusPlus) { if (getLangOptions().CPlusPlus) {
// C++ 8.3.5p2: If the parameter-declaration-clause is empty, the // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the
// function takes no arguments. // function takes no arguments.
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic); T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals);
} else { } else {
// Simple void foo(), where the incoming T is the result type. // Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionTypeNoProto(T); T = Context.getFunctionTypeNoProto(T);
@ -482,7 +482,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
ArgTys.push_back(ArgTy); ArgTys.push_back(ArgTy);
} }
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
FTI.isVariadic); FTI.isVariadic, FTI.TypeQuals);
} }
break; break;
} }
@ -492,6 +492,31 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
ProcessTypeAttributeList(T, AL); 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 // If there were any type attributes applied to the decl itself (not the
// type, apply the type attribute to the type!) // type, apply the type attribute to the type!)
if (const AttributeList *Attrs = D.getAttributes()) if (const AttributeList *Attrs = D.getAttributes())

View File

@ -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;
};