2006-11-08 14:54:53 +08:00
|
|
|
//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
|
2006-08-04 12:39:53 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-08-04 12:39:53 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2006-11-08 14:54:53 +08:00
|
|
|
// This file implements semantic analysis for declaration specifiers.
|
2006-08-04 12:39:53 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-11-12 07:03:42 +08:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2009-01-29 13:15:15 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2009-04-02 06:41:11 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2006-08-04 13:25:55 +08:00
|
|
|
#include "clang/Basic/LangOptions.h"
|
2009-01-21 03:11:22 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
#include <cstring>
|
2006-08-04 12:39:53 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2008-11-22 16:32:36 +08:00
|
|
|
|
|
|
|
static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
|
|
|
|
SourceManager &SrcMgr, unsigned DiagID) {
|
|
|
|
return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID);
|
|
|
|
}
|
|
|
|
|
2009-01-21 03:11:22 +08:00
|
|
|
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
|
|
|
|
/// "TheDeclarator" is the declarator that this will be added to.
|
|
|
|
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
|
2009-02-18 15:07:28 +08:00
|
|
|
SourceLocation EllipsisLoc,
|
2009-01-21 03:11:22 +08:00
|
|
|
ParamInfo *ArgInfo,
|
|
|
|
unsigned NumArgs,
|
|
|
|
unsigned TypeQuals,
|
2009-04-30 01:30:04 +08:00
|
|
|
bool hasExceptionSpec,
|
2009-05-31 19:47:27 +08:00
|
|
|
SourceLocation ThrowLoc,
|
2009-04-30 01:30:04 +08:00
|
|
|
bool hasAnyExceptionSpec,
|
|
|
|
ActionBase::TypeTy **Exceptions,
|
2009-05-30 02:02:33 +08:00
|
|
|
SourceRange *ExceptionRanges,
|
2009-04-30 01:30:04 +08:00
|
|
|
unsigned NumExceptions,
|
2009-01-21 03:11:22 +08:00
|
|
|
SourceLocation Loc,
|
|
|
|
Declarator &TheDeclarator) {
|
|
|
|
DeclaratorChunk I;
|
2009-04-30 01:30:04 +08:00
|
|
|
I.Kind = Function;
|
|
|
|
I.Loc = Loc;
|
|
|
|
I.Fun.hasPrototype = hasProto;
|
|
|
|
I.Fun.isVariadic = isVariadic;
|
|
|
|
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
|
|
|
|
I.Fun.DeleteArgInfo = false;
|
|
|
|
I.Fun.TypeQuals = TypeQuals;
|
|
|
|
I.Fun.NumArgs = NumArgs;
|
|
|
|
I.Fun.ArgInfo = 0;
|
|
|
|
I.Fun.hasExceptionSpec = hasExceptionSpec;
|
2009-05-31 19:47:27 +08:00
|
|
|
I.Fun.ThrowLoc = ThrowLoc.getRawEncoding();
|
2009-04-30 01:30:04 +08:00
|
|
|
I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec;
|
|
|
|
I.Fun.NumExceptions = NumExceptions;
|
|
|
|
I.Fun.Exceptions = 0;
|
|
|
|
|
2009-01-21 03:11:22 +08:00
|
|
|
// new[] an argument array if needed.
|
|
|
|
if (NumArgs) {
|
|
|
|
// If the 'InlineParams' in Declarator is unused and big enough, put our
|
|
|
|
// parameter list there (in an effort to avoid new/delete traffic). If it
|
|
|
|
// is already used (consider a function returning a function pointer) or too
|
|
|
|
// small (function taking too many arguments), go to the heap.
|
|
|
|
if (!TheDeclarator.InlineParamsUsed &&
|
|
|
|
NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
|
|
|
|
I.Fun.ArgInfo = TheDeclarator.InlineParams;
|
|
|
|
I.Fun.DeleteArgInfo = false;
|
|
|
|
TheDeclarator.InlineParamsUsed = true;
|
|
|
|
} else {
|
|
|
|
I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs];
|
|
|
|
I.Fun.DeleteArgInfo = true;
|
|
|
|
}
|
|
|
|
memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs);
|
|
|
|
}
|
2009-04-30 01:30:04 +08:00
|
|
|
// new[] an exception array if needed
|
|
|
|
if (NumExceptions) {
|
2009-05-30 02:02:33 +08:00
|
|
|
I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
|
|
|
|
for (unsigned i = 0; i != NumExceptions; ++i) {
|
|
|
|
I.Fun.Exceptions[i].Ty = Exceptions[i];
|
|
|
|
I.Fun.Exceptions[i].Range = ExceptionRanges[i];
|
|
|
|
}
|
2009-04-30 01:30:04 +08:00
|
|
|
}
|
2009-01-21 03:11:22 +08:00
|
|
|
return I;
|
|
|
|
}
|
2008-11-22 16:32:36 +08:00
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
|
2009-02-28 02:35:46 +08:00
|
|
|
/// declaration specifier includes.
|
2006-08-04 12:39:53 +08:00
|
|
|
///
|
|
|
|
unsigned DeclSpec::getParsedSpecifiers() const {
|
|
|
|
unsigned Res = 0;
|
2006-08-05 11:28:50 +08:00
|
|
|
if (StorageClassSpec != SCS_unspecified ||
|
|
|
|
SCS_thread_specified)
|
2006-08-04 12:39:53 +08:00
|
|
|
Res |= PQ_StorageClassSpecifier;
|
2008-06-20 03:52:46 +08:00
|
|
|
|
2006-11-28 13:05:08 +08:00
|
|
|
if (TypeQualifiers != TQ_unspecified)
|
2006-08-04 12:39:53 +08:00
|
|
|
Res |= PQ_TypeQualifier;
|
|
|
|
|
2006-11-28 12:28:12 +08:00
|
|
|
if (hasTypeSpecifier())
|
2006-08-04 12:39:53 +08:00
|
|
|
Res |= PQ_TypeSpecifier;
|
|
|
|
|
2008-10-31 17:07:45 +08:00
|
|
|
if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified)
|
2006-08-04 12:39:53 +08:00
|
|
|
Res |= PQ_FunctionSpecifier;
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2007-01-23 12:35:33 +08:00
|
|
|
const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
|
2006-08-05 11:28:50 +08:00
|
|
|
switch (S) {
|
|
|
|
default: assert(0 && "Unknown typespec!");
|
|
|
|
case DeclSpec::SCS_unspecified: return "unspecified";
|
|
|
|
case DeclSpec::SCS_typedef: return "typedef";
|
|
|
|
case DeclSpec::SCS_extern: return "extern";
|
|
|
|
case DeclSpec::SCS_static: return "static";
|
|
|
|
case DeclSpec::SCS_auto: return "auto";
|
|
|
|
case DeclSpec::SCS_register: return "register";
|
2009-04-20 04:27:55 +08:00
|
|
|
case DeclSpec::SCS_private_extern: return "__private_extern__";
|
2008-11-15 07:42:31 +08:00
|
|
|
case DeclSpec::SCS_mutable: return "mutable";
|
2006-08-05 11:28:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-12 12:08:59 +08:00
|
|
|
bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) {
|
|
|
|
PrevSpec = getSpecifierName(S);
|
2006-08-05 11:28:50 +08:00
|
|
|
return true;
|
|
|
|
}
|
2006-08-04 12:39:53 +08:00
|
|
|
|
2008-02-12 12:08:59 +08:00
|
|
|
bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) {
|
2006-08-04 12:39:53 +08:00
|
|
|
switch (W) {
|
2008-02-12 12:08:59 +08:00
|
|
|
case TSW_unspecified: PrevSpec = "unspecified"; break;
|
|
|
|
case TSW_short: PrevSpec = "short"; break;
|
|
|
|
case TSW_long: PrevSpec = "long"; break;
|
|
|
|
case TSW_longlong: PrevSpec = "long long"; break;
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-02-12 12:08:59 +08:00
|
|
|
bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) {
|
2006-08-04 12:39:53 +08:00
|
|
|
switch (C) {
|
2008-02-12 12:08:59 +08:00
|
|
|
case TSC_unspecified: PrevSpec = "unspecified"; break;
|
|
|
|
case TSC_imaginary: PrevSpec = "imaginary"; break;
|
|
|
|
case TSC_complex: PrevSpec = "complex"; break;
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-12 12:08:59 +08:00
|
|
|
bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) {
|
2006-08-04 12:39:53 +08:00
|
|
|
switch (S) {
|
2008-02-12 12:08:59 +08:00
|
|
|
case TSS_unspecified: PrevSpec = "unspecified"; break;
|
|
|
|
case TSS_signed: PrevSpec = "signed"; break;
|
|
|
|
case TSS_unsigned: PrevSpec = "unsigned"; break;
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-01-23 12:34:43 +08:00
|
|
|
const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
|
2006-08-04 12:39:53 +08:00
|
|
|
switch (T) {
|
2006-08-04 14:15:52 +08:00
|
|
|
default: assert(0 && "Unknown typespec!");
|
|
|
|
case DeclSpec::TST_unspecified: return "unspecified";
|
|
|
|
case DeclSpec::TST_void: return "void";
|
|
|
|
case DeclSpec::TST_char: return "char";
|
2008-08-10 00:51:54 +08:00
|
|
|
case DeclSpec::TST_wchar: return "wchar_t";
|
2009-07-14 14:30:34 +08:00
|
|
|
case DeclSpec::TST_char16: return "char16_t";
|
|
|
|
case DeclSpec::TST_char32: return "char32_t";
|
2006-08-04 14:15:52 +08:00
|
|
|
case DeclSpec::TST_int: return "int";
|
|
|
|
case DeclSpec::TST_float: return "float";
|
|
|
|
case DeclSpec::TST_double: return "double";
|
|
|
|
case DeclSpec::TST_bool: return "_Bool";
|
|
|
|
case DeclSpec::TST_decimal32: return "_Decimal32";
|
|
|
|
case DeclSpec::TST_decimal64: return "_Decimal64";
|
|
|
|
case DeclSpec::TST_decimal128: return "_Decimal128";
|
2006-08-14 06:16:42 +08:00
|
|
|
case DeclSpec::TST_enum: return "enum";
|
2008-04-14 02:59:07 +08:00
|
|
|
case DeclSpec::TST_class: return "class";
|
2006-08-14 06:16:42 +08:00
|
|
|
case DeclSpec::TST_union: return "union";
|
|
|
|
case DeclSpec::TST_struct: return "struct";
|
2009-02-09 23:09:02 +08:00
|
|
|
case DeclSpec::TST_typename: return "type-name";
|
2007-07-31 20:34:36 +08:00
|
|
|
case DeclSpec::TST_typeofType:
|
|
|
|
case DeclSpec::TST_typeofExpr: return "typeof";
|
2009-06-27 02:41:36 +08:00
|
|
|
case DeclSpec::TST_auto: return "auto";
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
2006-08-04 14:15:52 +08:00
|
|
|
}
|
|
|
|
|
2008-02-12 12:08:59 +08:00
|
|
|
bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) {
|
|
|
|
PrevSpec = getSpecifierName(T);
|
2006-08-04 12:39:53 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-02-12 12:08:59 +08:00
|
|
|
bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) {
|
2006-08-04 13:25:55 +08:00
|
|
|
switch (T) {
|
|
|
|
case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break;
|
|
|
|
case DeclSpec::TQ_const: PrevSpec = "const"; break;
|
|
|
|
case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break;
|
|
|
|
case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2006-08-04 12:39:53 +08:00
|
|
|
|
2006-11-28 13:05:08 +08:00
|
|
|
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
|
|
|
|
const char *&PrevSpec) {
|
2006-08-05 11:28:50 +08:00
|
|
|
if (StorageClassSpec != SCS_unspecified)
|
2008-11-22 16:32:36 +08:00
|
|
|
return BadSpecifier((SCS)StorageClassSpec, PrevSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
StorageClassSpec = S;
|
2006-11-28 13:05:08 +08:00
|
|
|
StorageClassSpecLoc = Loc;
|
2008-11-15 07:42:31 +08:00
|
|
|
assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
|
2006-08-05 11:28:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-11-28 13:05:08 +08:00
|
|
|
bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
|
|
|
|
const char *&PrevSpec) {
|
2006-11-28 12:50:12 +08:00
|
|
|
if (SCS_thread_specified) {
|
|
|
|
PrevSpec = "__thread";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
SCS_thread_specified = true;
|
2006-11-28 13:05:08 +08:00
|
|
|
SCS_threadLoc = Loc;
|
2006-11-28 12:50:12 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-08-05 11:28:50 +08:00
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
/// These methods set the specified attribute of the DeclSpec, but return true
|
|
|
|
/// and ignore the request if invalid (e.g. "extern" then "auto" is
|
|
|
|
/// specified).
|
2006-11-28 13:30:29 +08:00
|
|
|
bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
|
|
|
|
const char *&PrevSpec) {
|
2006-11-28 12:50:12 +08:00
|
|
|
if (TypeSpecWidth != TSW_unspecified &&
|
|
|
|
// Allow turning long -> long long.
|
|
|
|
(W != TSW_longlong || TypeSpecWidth != TSW_long))
|
2008-11-22 16:32:36 +08:00
|
|
|
return BadSpecifier((TSW)TypeSpecWidth, PrevSpec);
|
2006-08-04 12:39:53 +08:00
|
|
|
TypeSpecWidth = W;
|
2006-11-28 13:30:29 +08:00
|
|
|
TSWLoc = Loc;
|
2006-08-04 12:39:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-11-28 13:30:29 +08:00
|
|
|
bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
|
|
|
|
const char *&PrevSpec) {
|
2006-08-04 12:39:53 +08:00
|
|
|
if (TypeSpecComplex != TSC_unspecified)
|
2008-11-22 16:32:36 +08:00
|
|
|
return BadSpecifier((TSC)TypeSpecComplex, PrevSpec);
|
2006-08-04 12:39:53 +08:00
|
|
|
TypeSpecComplex = C;
|
2006-11-28 13:30:29 +08:00
|
|
|
TSCLoc = Loc;
|
2006-08-04 12:39:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-11-28 13:30:29 +08:00
|
|
|
bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
|
|
|
|
const char *&PrevSpec) {
|
2006-08-04 12:39:53 +08:00
|
|
|
if (TypeSpecSign != TSS_unspecified)
|
2008-11-22 16:32:36 +08:00
|
|
|
return BadSpecifier((TSS)TypeSpecSign, PrevSpec);
|
2006-08-04 13:26:52 +08:00
|
|
|
TypeSpecSign = S;
|
2006-11-28 13:30:29 +08:00
|
|
|
TSSLoc = Loc;
|
2006-08-04 12:39:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-11-28 13:30:29 +08:00
|
|
|
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
const char *&PrevSpec, void *Rep,
|
|
|
|
bool Owned) {
|
2006-08-04 12:39:53 +08:00
|
|
|
if (TypeSpecType != TST_unspecified)
|
2008-11-22 16:32:36 +08:00
|
|
|
return BadSpecifier((TST)TypeSpecType, PrevSpec);
|
2006-08-04 13:26:52 +08:00
|
|
|
TypeSpecType = T;
|
2007-01-23 12:58:34 +08:00
|
|
|
TypeRep = Rep;
|
2006-11-28 13:30:29 +08:00
|
|
|
TSTLoc = Loc;
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
TypeSpecOwned = Owned;
|
2006-08-04 12:39:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-02-07 06:42:48 +08:00
|
|
|
bool DeclSpec::SetTypeSpecError() {
|
|
|
|
TypeSpecType = TST_error;
|
|
|
|
TypeRep = 0;
|
|
|
|
TSTLoc = SourceLocation();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-11-28 13:18:46 +08:00
|
|
|
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
|
2006-08-04 13:25:55 +08:00
|
|
|
const LangOptions &Lang) {
|
|
|
|
// Duplicates turn into warnings pre-C99.
|
|
|
|
if ((TypeQualifiers & T) && !Lang.C99)
|
|
|
|
return BadSpecifier(T, PrevSpec);
|
|
|
|
TypeQualifiers |= T;
|
2006-11-28 13:18:46 +08:00
|
|
|
|
|
|
|
switch (T) {
|
|
|
|
default: assert(0 && "Unknown type qualifier!");
|
|
|
|
case TQ_const: TQ_constLoc = Loc; break;
|
|
|
|
case TQ_restrict: TQ_restrictLoc = Loc; break;
|
|
|
|
case TQ_volatile: TQ_volatileLoc = Loc; break;
|
|
|
|
}
|
2006-08-04 13:25:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
2006-08-04 12:39:53 +08:00
|
|
|
|
2006-11-28 13:12:07 +08:00
|
|
|
bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){
|
2006-11-28 12:33:46 +08:00
|
|
|
// 'inline inline' is ok.
|
|
|
|
FS_inline_specified = true;
|
2006-11-28 13:12:07 +08:00
|
|
|
FS_inlineLoc = Loc;
|
2006-11-28 12:33:46 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-10-31 17:07:45 +08:00
|
|
|
bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec){
|
|
|
|
// 'virtual virtual' is ok.
|
|
|
|
FS_virtual_specified = true;
|
|
|
|
FS_virtualLoc = Loc;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec){
|
|
|
|
// 'explicit explicit' is ok.
|
|
|
|
FS_explicit_specified = true;
|
|
|
|
FS_explicitLoc = Loc;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-05-06 12:46:28 +08:00
|
|
|
bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec) {
|
|
|
|
if (Friend_specified) {
|
|
|
|
PrevSpec = "friend";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Friend_specified = true;
|
|
|
|
FriendLoc = Loc;
|
|
|
|
return false;
|
|
|
|
}
|
2006-11-28 12:33:46 +08:00
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
/// Finish - This does final analysis of the declspec, rejecting things like
|
|
|
|
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
|
|
|
|
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
|
|
|
|
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
|
2009-04-02 06:41:11 +08:00
|
|
|
void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
|
2006-08-04 14:36:52 +08:00
|
|
|
// Check the type specifier components first.
|
2009-04-02 06:41:11 +08:00
|
|
|
SourceManager &SrcMgr = PP.getSourceManager();
|
2006-08-04 14:36:52 +08:00
|
|
|
|
2008-08-10 00:51:54 +08:00
|
|
|
// signed/unsigned are only valid with int/char/wchar_t.
|
2006-08-04 14:15:52 +08:00
|
|
|
if (TypeSpecSign != TSS_unspecified) {
|
2006-08-04 14:36:52 +08:00
|
|
|
if (TypeSpecType == TST_unspecified)
|
|
|
|
TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
|
2008-08-10 00:51:54 +08:00
|
|
|
else if (TypeSpecType != TST_int &&
|
|
|
|
TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
|
2008-11-22 16:32:36 +08:00
|
|
|
Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec)
|
|
|
|
<< getSpecifierName((TST)TypeSpecType);
|
2006-08-04 14:36:52 +08:00
|
|
|
// signed double -> double.
|
2006-08-04 14:15:52 +08:00
|
|
|
TypeSpecSign = TSS_unspecified;
|
|
|
|
}
|
|
|
|
}
|
2006-08-04 14:36:52 +08:00
|
|
|
|
2006-08-04 14:15:52 +08:00
|
|
|
// Validate the width of the type.
|
|
|
|
switch (TypeSpecWidth) {
|
|
|
|
case TSW_unspecified: break;
|
|
|
|
case TSW_short: // short int
|
|
|
|
case TSW_longlong: // long long int
|
2006-08-04 14:36:52 +08:00
|
|
|
if (TypeSpecType == TST_unspecified)
|
|
|
|
TypeSpecType = TST_int; // short -> short int, long long -> long long int.
|
|
|
|
else if (TypeSpecType != TST_int) {
|
2007-12-12 05:27:55 +08:00
|
|
|
Diag(D, TSWLoc, SrcMgr,
|
2007-05-17 01:49:37 +08:00
|
|
|
TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
|
2008-11-22 16:32:36 +08:00
|
|
|
: diag::err_invalid_longlong_spec)
|
|
|
|
<< getSpecifierName((TST)TypeSpecType);
|
2006-08-04 14:15:52 +08:00
|
|
|
TypeSpecType = TST_int;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TSW_long: // long double, long int
|
2006-08-04 14:36:52 +08:00
|
|
|
if (TypeSpecType == TST_unspecified)
|
|
|
|
TypeSpecType = TST_int; // long -> long int.
|
|
|
|
else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
|
2008-11-22 16:32:36 +08:00
|
|
|
Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec)
|
|
|
|
<< getSpecifierName((TST)TypeSpecType);
|
2006-08-04 14:15:52 +08:00
|
|
|
TypeSpecType = TST_int;
|
|
|
|
}
|
2006-08-04 14:36:52 +08:00
|
|
|
break;
|
2006-08-04 14:15:52 +08:00
|
|
|
}
|
2006-08-04 12:39:53 +08:00
|
|
|
|
2006-08-14 03:58:17 +08:00
|
|
|
// TODO: if the implementation does not implement _Complex or _Imaginary,
|
2006-08-04 14:36:52 +08:00
|
|
|
// disallow their use. Need information about the backend.
|
|
|
|
if (TypeSpecComplex != TSC_unspecified) {
|
|
|
|
if (TypeSpecType == TST_unspecified) {
|
2009-04-02 06:41:11 +08:00
|
|
|
Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex)
|
|
|
|
<< CodeModificationHint::CreateInsertion(
|
|
|
|
PP.getLocForEndOfToken(getTypeSpecComplexLoc()),
|
|
|
|
" double");
|
2006-08-04 14:36:52 +08:00
|
|
|
TypeSpecType = TST_double; // _Complex -> _Complex double.
|
|
|
|
} else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
|
2006-08-05 11:28:50 +08:00
|
|
|
// Note that this intentionally doesn't include _Complex _Bool.
|
2007-12-12 05:27:55 +08:00
|
|
|
Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex);
|
2006-08-04 14:36:52 +08:00
|
|
|
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
|
2008-11-22 16:32:36 +08:00
|
|
|
Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec)
|
|
|
|
<< getSpecifierName((TST)TypeSpecType);
|
2006-08-04 14:36:52 +08:00
|
|
|
TypeSpecComplex = TSC_unspecified;
|
|
|
|
}
|
|
|
|
}
|
2006-08-05 11:30:45 +08:00
|
|
|
|
|
|
|
// Okay, now we can infer the real type.
|
|
|
|
|
2006-08-14 03:58:17 +08:00
|
|
|
// TODO: return "auto function" and other bad things based on the real type.
|
2006-08-05 11:28:50 +08:00
|
|
|
|
2006-08-04 14:42:31 +08:00
|
|
|
// 'data definition has no type or storage class'?
|
2006-08-04 12:39:53 +08:00
|
|
|
}
|
2008-08-11 11:45:03 +08:00
|
|
|
|
2008-12-28 23:28:59 +08:00
|
|
|
bool DeclSpec::isMissingDeclaratorOk() {
|
|
|
|
TST tst = getTypeSpecType();
|
|
|
|
return (tst == TST_union
|
|
|
|
|| tst == TST_struct
|
|
|
|
|| tst == TST_class
|
|
|
|
|| tst == TST_enum
|
2009-01-13 06:49:06 +08:00
|
|
|
) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef;
|
2008-12-28 23:28:59 +08:00
|
|
|
}
|