Skip to content

Commit 22c40fa

Browse files
committed
-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
1 parent c157586 commit 22c40fa

File tree

14 files changed

+139
-31
lines changed

14 files changed

+139
-31
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ class ASTContext {
208208
/// getFunctionType - Return a normal function type with a typed argument
209209
/// list. isVariadic indicates whether the argument list includes '...'.
210210
QualType getFunctionType(QualType ResultTy, const QualType *ArgArray,
211-
unsigned NumArgs, bool isVariadic);
211+
unsigned NumArgs, bool isVariadic,
212+
unsigned TypeQuals = 0);
212213

213214
/// getTypeDeclType - Return the unique reference to the type for
214215
/// the specified type declaration.

clang/include/clang/AST/DeclCXX.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ class CXXMethodDecl : public FunctionDecl {
230230
/// Should only be called for instance methods.
231231
QualType getThisType(ASTContext &C) const;
232232

233+
unsigned getTypeQualifiers() const {
234+
return getType()->getAsFunctionTypeProto()->getTypeQuals();
235+
}
236+
233237
// Implement isa/cast/dyncast/etc.
234238
static bool classof(const Decl *D) { return D->getKind() == CXXMethod; }
235239
static bool classof(const CXXMethodDecl *D) { return true; }

clang/include/clang/AST/Type.h

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ class QualType {
157157
QualType getWithAdditionalQualifiers(unsigned TQs) const {
158158
return QualType(getTypePtr(), TQs|getCVRQualifiers());
159159
}
160+
161+
QualType withConst() const { return getWithAdditionalQualifiers(Const); }
162+
QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);}
163+
QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);}
160164

161165
QualType getUnqualifiedType() const;
162166
bool isMoreQualifiedThan(QualType Other) const;
@@ -917,13 +921,25 @@ class FunctionType : public Type {
917921
/// SubClassData - This field is owned by the subclass, put here to pack
918922
/// tightly with the ivars in Type.
919923
bool SubClassData : 1;
924+
925+
/// TypeQuals - Used only by FunctionTypeProto, put here to pack with the
926+
/// other bitfields.
927+
/// The qualifiers are part of FunctionTypeProto because...
928+
///
929+
/// C++ 8.3.5p4: The return type, the parameter type list and the
930+
/// cv-qualifier-seq, [...], are part of the function type.
931+
///
932+
unsigned TypeQuals : 3;
920933

921934
// The type returned by the function.
922935
QualType ResultType;
923936
protected:
924-
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,QualType Canonical)
925-
: Type(tc, Canonical), SubClassData(SubclassInfo), ResultType(res) {}
937+
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
938+
unsigned typeQuals, QualType Canonical)
939+
: Type(tc, Canonical),
940+
SubClassData(SubclassInfo), TypeQuals(typeQuals), ResultType(res) {}
926941
bool getSubClassData() const { return SubClassData; }
942+
unsigned getTypeQuals() const { return TypeQuals; }
927943
public:
928944

929945
QualType getResultType() const { return ResultType; }
@@ -940,7 +956,7 @@ class FunctionType : public Type {
940956
/// no information available about its arguments.
941957
class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode {
942958
FunctionTypeNoProto(QualType Result, QualType Canonical)
943-
: FunctionType(FunctionNoProto, Result, false, Canonical) {}
959+
: FunctionType(FunctionNoProto, Result, false, 0, Canonical) {}
944960
friend class ASTContext; // ASTContext creates these.
945961
public:
946962
// No additional state past what FunctionType provides.
@@ -970,8 +986,8 @@ class FunctionTypeNoProto : public FunctionType, public llvm::FoldingSetNode {
970986
/// arguments, not as having a single void argument.
971987
class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode {
972988
FunctionTypeProto(QualType Result, const QualType *ArgArray, unsigned numArgs,
973-
bool isVariadic, QualType Canonical)
974-
: FunctionType(FunctionProto, Result, isVariadic, Canonical),
989+
bool isVariadic, unsigned typeQuals, QualType Canonical)
990+
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical),
975991
NumArgs(numArgs) {
976992
// Fill in the trailing argument array.
977993
QualType *ArgInfo = reinterpret_cast<QualType *>(this+1);;
@@ -996,6 +1012,7 @@ class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode {
9961012
}
9971013

9981014
bool isVariadic() const { return getSubClassData(); }
1015+
unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
9991016

10001017
typedef const QualType *arg_type_iterator;
10011018
arg_type_iterator arg_type_begin() const {
@@ -1013,7 +1030,7 @@ class FunctionTypeProto : public FunctionType, public llvm::FoldingSetNode {
10131030
void Profile(llvm::FoldingSetNodeID &ID);
10141031
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
10151032
arg_type_iterator ArgTys, unsigned NumArgs,
1016-
bool isVariadic);
1033+
bool isVariadic, unsigned TypeQuals);
10171034

10181035
protected:
10191036
virtual void EmitImpl(llvm::Serializer& S) const;

clang/include/clang/Basic/DiagnosticKinds.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,11 @@ DIAG(err_invalid_this_use, ERROR,
10411041
"invalid use of 'this' outside of a nonstatic member function")
10421042
DIAG(err_invalid_member_use_in_static_method, ERROR,
10431043
"invalid use of member '%0' in static member function")
1044+
DIAG(err_invalid_qualified_function_type, ERROR,
1045+
"type qualifier is not allowed on this function")
1046+
DIAG(err_invalid_qualified_typedef_function_type_use, ERROR,
1047+
"a qualified function type cannot be used to declare a nonmember function "
1048+
"or a static member function")
10441049
DIAG(err_invalid_non_static_member_use, ERROR,
10451050
"invalid use of nonstatic data member '%0'")
10461051
DIAG(err_invalid_incomplete_type_use, ERROR,

clang/include/clang/Parse/DeclSpec.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ struct DeclaratorChunk {
442442
/// with ',...)', this is true.
443443
bool isVariadic : 1;
444444

445+
/// The type qualifiers: const/volatile/restrict.
446+
/// The qualifier bitmask values are the same as in QualType.
447+
unsigned TypeQuals : 3;
448+
445449
/// NumArgs - This is the number of formal arguments provided for the
446450
/// declarator.
447451
unsigned NumArgs;
@@ -528,12 +532,13 @@ struct DeclaratorChunk {
528532
/// getFunction - Return a DeclaratorChunk for a function.
529533
static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
530534
ParamInfo *ArgInfo, unsigned NumArgs,
531-
SourceLocation Loc) {
535+
unsigned TypeQuals, SourceLocation Loc) {
532536
DeclaratorChunk I;
533537
I.Kind = Function;
534538
I.Loc = Loc;
535539
I.Fun.hasPrototype = hasProto;
536540
I.Fun.isVariadic = isVariadic;
541+
I.Fun.TypeQuals = TypeQuals;
537542
I.Fun.NumArgs = NumArgs;
538543
I.Fun.ArgInfo = 0;
539544

clang/lib/AST/ASTContext.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -884,11 +884,13 @@ QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) {
884884
/// getFunctionType - Return a normal function type with a typed argument
885885
/// list. isVariadic indicates whether the argument list includes '...'.
886886
QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
887-
unsigned NumArgs, bool isVariadic) {
887+
unsigned NumArgs, bool isVariadic,
888+
unsigned TypeQuals) {
888889
// Unique functions, to guarantee there is only one function of a particular
889890
// structure.
890891
llvm::FoldingSetNodeID ID;
891-
FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic);
892+
FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
893+
TypeQuals);
892894

893895
void *InsertPos = 0;
894896
if (FunctionTypeProto *FTP =
@@ -925,7 +927,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
925927
(FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) +
926928
NumArgs*sizeof(QualType));
927929
new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic,
928-
Canonical);
930+
TypeQuals, Canonical);
929931
Types.push_back(FTP);
930932
FunctionTypeProtos.InsertNode(FTP, InsertPos);
931933
return QualType(FTP, 0);

clang/lib/AST/DeclCXX.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,8 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
6464
assert(isInstance() && "No 'this' for static methods!");
6565
QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(
6666
cast<CXXRecordDecl>(getParent())));
67-
QualType ThisTy = C.getPointerType(ClassTy);
68-
ThisTy.addConst();
69-
return ThisTy;
67+
ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers());
68+
return C.getPointerType(ClassTy).withConst();
7069
}
7170

7271
CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,

clang/lib/AST/Type.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,15 +705,18 @@ const char *BuiltinType::getName() const {
705705

706706
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
707707
arg_type_iterator ArgTys,
708-
unsigned NumArgs, bool isVariadic) {
708+
unsigned NumArgs, bool isVariadic,
709+
unsigned TypeQuals) {
709710
ID.AddPointer(Result.getAsOpaquePtr());
710711
for (unsigned i = 0; i != NumArgs; ++i)
711712
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
712713
ID.AddInteger(isVariadic);
714+
ID.AddInteger(TypeQuals);
713715
}
714716

715717
void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) {
716-
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic());
718+
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
719+
getTypeQuals());
717720
}
718721

719722
void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D) {
12131213
/// direct-declarator '(' identifier-list[opt] ')'
12141214
/// [GNU] direct-declarator '(' parameter-forward-declarations
12151215
/// parameter-type-list[opt] ')'
1216+
/// [C++] direct-declarator '(' parameter-declaration-clause ')'
1217+
/// cv-qualifier-seq[opt] exception-specification[opt]
12161218
///
12171219
void Parser::ParseDirectDeclarator(Declarator &D) {
12181220
// Parse the first direct-declarator seen.
@@ -1371,6 +1373,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {
13711373
/// '=' assignment-expression
13721374
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
13731375
///
1376+
/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]"
1377+
/// and "exception-specification[opt]"(TODO).
1378+
///
13741379
void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
13751380
AttributeList *AttrList,
13761381
bool RequiresArg) {
@@ -1383,20 +1388,29 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
13831388
Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);
13841389
delete AttrList;
13851390
}
1386-
1391+
1392+
ConsumeParen(); // Eat the closing ')'.
1393+
1394+
// cv-qualifier-seq[opt].
1395+
DeclSpec DS;
1396+
if (getLang().CPlusPlus) {
1397+
ParseTypeQualifierListOpt(DS);
1398+
// FIXME: Parse exception-specification[opt].
1399+
}
1400+
13871401
// Remember that we parsed a function type, and remember the attributes.
13881402
// int() -> no prototype, no '...'.
1389-
D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/ false,
1403+
D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
13901404
/*variadic*/ false,
1391-
/*arglist*/ 0, 0, LParenLoc));
1392-
1393-
ConsumeParen(); // Eat the closing ')'.
1405+
/*arglist*/ 0, 0,
1406+
DS.getTypeQualifiers(),
1407+
LParenLoc));
13941408
return;
13951409
}
13961410

13971411
// Alternatively, this parameter list may be an identifier list form for a
13981412
// K&R-style function: void foo(a,b,c)
1399-
if (Tok.is(tok::identifier) &&
1413+
if (!getLang().CPlusPlus && Tok.is(tok::identifier) &&
14001414
// K&R identifier lists can't have typedefs as identifiers, per
14011415
// C99 6.7.5.3p11.
14021416
!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
@@ -1508,13 +1522,21 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
15081522
// Leave prototype scope.
15091523
ExitScope();
15101524

1525+
// If we have the closing ')', eat it.
1526+
MatchRHSPunctuation(tok::r_paren, LParenLoc);
1527+
1528+
// cv-qualifier-seq[opt].
1529+
DeclSpec DS;
1530+
if (getLang().CPlusPlus) {
1531+
ParseTypeQualifierListOpt(DS);
1532+
// FIXME: Parse exception-specification[opt].
1533+
}
1534+
15111535
// Remember that we parsed a function type, and remember the attributes.
15121536
D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
15131537
&ParamInfo[0], ParamInfo.size(),
1538+
DS.getTypeQualifiers(),
15141539
LParenLoc));
1515-
1516-
// If we have the closing ')', eat it and we're done.
1517-
MatchRHSPunctuation(tok::r_paren, LParenLoc);
15181540
}
15191541

15201542
/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
@@ -1581,7 +1603,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
15811603
// has no prototype.
15821604
D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
15831605
&ParamInfo[0], ParamInfo.size(),
1584-
LParenLoc));
1606+
/*TypeQuals*/0, LParenLoc));
15851607

15861608
// If we have the closing ')', eat it and we're done.
15871609
MatchRHSPunctuation(tok::r_paren, LParenLoc);

clang/lib/Parse/ParseExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ Parser::ExprResult Parser::ParseBlockLiteralExpression() {
11161116
} else {
11171117
// Otherwise, pretend we saw (void).
11181118
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
1119-
0, 0, CaretLoc));
1119+
0, 0, 0, CaretLoc));
11201120
}
11211121

11221122
// Inform sema that we are starting a block.

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1820,7 +1820,7 @@ ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
18201820
Error = Error; // Silence warning.
18211821
assert(!Error && "Error setting up implicit decl!");
18221822
Declarator D(DS, Declarator::BlockContext);
1823-
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, Loc));
1823+
D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, 0, Loc));
18241824
D.SetIdentifier(&II, Loc);
18251825

18261826
// Insert this function into translation-unit scope.

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,9 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
402402
if (FD->isInvalidDecl())
403403
return true;
404404

405-
return new DeclRefExpr(FD, FD->getType(), Loc);
405+
// FIXME: Handle 'mutable'.
406+
return new DeclRefExpr(FD,
407+
FD->getType().getWithAdditionalQualifiers(MD->getTypeQualifiers()),Loc);
406408
}
407409

408410
return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName());

clang/lib/Sema/SemaType.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
409409
if (getLangOptions().CPlusPlus) {
410410
// C++ 8.3.5p2: If the parameter-declaration-clause is empty, the
411411
// function takes no arguments.
412-
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic);
412+
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals);
413413
} else {
414414
// Simple void foo(), where the incoming T is the result type.
415415
T = Context.getFunctionTypeNoProto(T);
@@ -482,7 +482,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
482482
ArgTys.push_back(ArgTy);
483483
}
484484
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
485-
FTI.isVariadic);
485+
FTI.isVariadic, FTI.TypeQuals);
486486
}
487487
break;
488488
}
@@ -491,6 +491,31 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
491491
if (const AttributeList *AL = DeclType.getAttrs())
492492
ProcessTypeAttributeList(T, AL);
493493
}
494+
495+
if (getLangOptions().CPlusPlus && T->isFunctionType()) {
496+
const FunctionTypeProto *FnTy = T->getAsFunctionTypeProto();
497+
assert(FnTy && "Why oh why is there not a FunctionTypeProto here ?");
498+
499+
// C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type
500+
// for a nonstatic member function, the function type to which a pointer
501+
// to member refers, or the top-level function type of a function typedef
502+
// declaration.
503+
if (FnTy->getTypeQuals() != 0 &&
504+
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
505+
(D.getContext() != Declarator::MemberContext ||
506+
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
507+
508+
if (D.isFunctionDeclarator())
509+
Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
510+
else
511+
Diag(D.getIdentifierLoc(),
512+
diag::err_invalid_qualified_typedef_function_type_use);
513+
514+
// Strip the cv-quals from the type.
515+
T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
516+
FnTy->getNumArgs(), FnTy->isVariadic());
517+
}
518+
}
494519

495520
// If there were any type attributes applied to the decl itself (not the
496521
// type, apply the type attribute to the type!)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: clang -fsyntax-only -verify %s
2+
3+
void f() const; // expected-error {{type qualifier is not allowed on this function}}
4+
5+
typedef void cfn() const;
6+
cfn f2; // expected-error {{a qualified function type cannot be used to declare a nonmember function or a static member function}}
7+
8+
class C {
9+
void f() const;
10+
cfn f2;
11+
static void f3() const; // expected-error {{type qualifier is not allowed on this function}}
12+
static cfn f4; // expected-error {{a qualified function type cannot be used to declare a nonmember function or a static member function}}
13+
14+
void m1() {
15+
x = 0;
16+
}
17+
18+
void m2() const {
19+
x = 0; // expected-error {{read-only variable is not assignable}}
20+
}
21+
22+
int x;
23+
};

0 commit comments

Comments
 (0)