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"
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
/// \brief Double the capacity of this scope specifier.
|
|
|
|
void CXXScopeSpec::reallocate() {
|
|
|
|
Action::CXXScopeTy **Data = new Action::CXXScopeTy *[Capacity * 2];
|
|
|
|
|
|
|
|
Action::CXXScopeTy **From
|
|
|
|
= Capacity == 4? &InlineScopeReps[0] : ManyScopeReps;
|
|
|
|
std::memcpy(Data, From, Capacity * sizeof(Action::CXXScopeTy *));
|
|
|
|
|
|
|
|
if (Capacity > 4)
|
|
|
|
delete [] ManyScopeReps;
|
|
|
|
ManyScopeReps = Data;
|
|
|
|
Capacity *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &SS)
|
|
|
|
: Range(SS.Range), NumScopeReps(SS.NumScopeReps), Capacity(SS.Capacity) {
|
|
|
|
|
|
|
|
if (Capacity > 4) {
|
|
|
|
ManyScopeReps = new Action::CXXScopeTy *[Capacity];
|
|
|
|
memcpy(ManyScopeReps, SS.ManyScopeReps,
|
|
|
|
Capacity * sizeof(Action::CXXScopeTy *));
|
|
|
|
} else {
|
|
|
|
memcpy(InlineScopeReps, SS.InlineScopeReps,
|
|
|
|
Capacity * sizeof(Action::CXXScopeTy *));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &SS) {
|
|
|
|
// FIXME: Does not provide the strong exception safety guarantee.
|
|
|
|
this->~CXXScopeSpec();
|
|
|
|
new (this) CXXScopeSpec(SS);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *CXXScopeSpec::buildAnnotationData() const {
|
|
|
|
uintptr_t *Data = (uintptr_t *)malloc(sizeof(uintptr_t) * (size() + 1));
|
|
|
|
Data[0] = size();
|
|
|
|
for (unsigned I = 0; I < size(); ++I)
|
|
|
|
Data[I + 1] = reinterpret_cast<uintptr_t>(getScopeRep(I));
|
|
|
|
return Data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CXXScopeSpec::setFromAnnotationData(void *DataIn) {
|
|
|
|
uintptr_t *Data = static_cast<uintptr_t *>(DataIn);
|
|
|
|
NumScopeReps = *Data;
|
|
|
|
|
|
|
|
// Allocate enough space for the annotation data.
|
|
|
|
if (NumScopeReps > Capacity) {
|
|
|
|
if (Capacity > 4)
|
|
|
|
delete [] ManyScopeReps;
|
|
|
|
|
|
|
|
Capacity = NumScopeReps;
|
|
|
|
ManyScopeReps = new Action::CXXScopeTy *[Capacity];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Capacity > 4)
|
|
|
|
std::memcpy(ManyScopeReps, Data + 1, sizeof(uintptr_t) * NumScopeReps);
|
|
|
|
else
|
|
|
|
std::memcpy(InlineScopeReps, Data + 1, sizeof(uintptr_t) * NumScopeReps);
|
|
|
|
}
|
2008-11-22 16:32:36 +08:00
|
|
|
|
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,
|
|
|
|
SourceLocation Loc,
|
|
|
|
Declarator &TheDeclarator) {
|
|
|
|
DeclaratorChunk I;
|
|
|
|
I.Kind = Function;
|
|
|
|
I.Loc = Loc;
|
|
|
|
I.Fun.hasPrototype = hasProto;
|
|
|
|
I.Fun.isVariadic = isVariadic;
|
2009-02-18 15:07:28 +08:00
|
|
|
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
|
2009-01-21 03:11:22 +08:00
|
|
|
I.Fun.DeleteArgInfo = false;
|
|
|
|
I.Fun.TypeQuals = TypeQuals;
|
|
|
|
I.Fun.NumArgs = NumArgs;
|
|
|
|
I.Fun.ArgInfo = 0;
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
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";
|
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";
|
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";
|
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,
|
2008-08-01 18:35:27 +08:00
|
|
|
const char *&PrevSpec, Action::TypeTy *Rep) {
|
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;
|
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;
|
|
|
|
}
|
|
|
|
|
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.
|
2007-12-12 05:27:55 +08:00
|
|
|
void DeclSpec::Finish(Diagnostic &D, SourceManager& SrcMgr,
|
|
|
|
const LangOptions &Lang) {
|
2006-08-04 14:36:52 +08:00
|
|
|
// Check the type specifier components first.
|
|
|
|
|
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) {
|
2007-12-12 05:27:55 +08:00
|
|
|
Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex);
|
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-04 14:42:31 +08:00
|
|
|
|
2006-08-05 11:28:50 +08:00
|
|
|
// Verify __thread.
|
|
|
|
if (SCS_thread_specified) {
|
|
|
|
if (StorageClassSpec == SCS_unspecified) {
|
|
|
|
StorageClassSpec = SCS_extern; // '__thread int' -> 'extern __thread int'
|
|
|
|
} else if (StorageClassSpec != SCS_extern &&
|
|
|
|
StorageClassSpec != SCS_static) {
|
2008-11-22 16:32:36 +08:00
|
|
|
Diag(D, getStorageClassSpecLoc(), SrcMgr, diag::err_invalid_thread_spec)
|
|
|
|
<< getSpecifierName((SCS)StorageClassSpec);
|
2006-08-05 11:28:50 +08:00
|
|
|
SCS_thread_specified = false;
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|