Emit diagnostics for things like 'signed _Bool' and 'short float'

llvm-svn: 38811
This commit is contained in:
Chris Lattner 2006-08-04 06:15:52 +00:00
parent 494f27a0b8
commit 839713c085
4 changed files with 64 additions and 22 deletions

View File

@ -13,6 +13,7 @@
#include "clang/Parse/Declarations.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
using namespace llvm;
using namespace clang;
@ -67,19 +68,24 @@ static bool BadSpecifier(DeclSpec::TSS S, const char *&PrevSpec) {
return true;
}
static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) {
static const char *getSpecifierName(DeclSpec::TST T) {
switch (T) {
case DeclSpec::TST_unspecified: PrevSpec = "unspecified"; break;
case DeclSpec::TST_void: PrevSpec = "void"; break;
case DeclSpec::TST_char: PrevSpec = "char"; break;
case DeclSpec::TST_int: PrevSpec = "int"; break;
case DeclSpec::TST_float: PrevSpec = "float"; break;
case DeclSpec::TST_double: PrevSpec = "double"; break;
case DeclSpec::TST_bool: PrevSpec = "_Bool"; break;
case DeclSpec::TST_decimal32: PrevSpec = "_Decimal32"; break;
case DeclSpec::TST_decimal64: PrevSpec = "_Decimal64"; break;
case DeclSpec::TST_decimal128: PrevSpec = "_Decimal128"; break;
default: assert(0 && "Unknown typespec!");
case DeclSpec::TST_unspecified: return "unspecified";
case DeclSpec::TST_void: return "void";
case DeclSpec::TST_char: return "char";
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";
}
}
static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) {
PrevSpec = getSpecifierName(T);
return true;
}
@ -143,8 +149,38 @@ bool DeclSpec::SetFuncSpec(FS F, const char *&PrevSpec) {
/// "_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.
diag::kind DeclSpec::Finish(const LangOptions &Lang) {
// FIXME: implement this.
void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D,
const LangOptions &Lang) {
// signed/unsigned are not valid with void,float,double,bool,decimal*.
if (TypeSpecSign != TSS_unspecified) {
if (TypeSpecType == TST_void || TypeSpecType == TST_float ||
TypeSpecType == TST_double || TypeSpecType == TST_bool ||
TypeSpecType == TST_decimal32 || TypeSpecType == TST_decimal64 ||
TypeSpecType == TST_decimal128) {
D.Report(Loc, diag::err_invalid_sign_spec,getSpecifierName(TypeSpecType));
TypeSpecSign = TSS_unspecified;
}
}
// Validate the width of the type.
switch (TypeSpecWidth) {
case TSW_unspecified: break;
case TSW_short: // short int
case TSW_longlong: // long long int
if (TypeSpecType != TST_unspecified && TypeSpecType != TST_int) {
D.Report(Loc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec :
diag::err_invalid_longlong_spec,
getSpecifierName(TypeSpecType));
TypeSpecType = TST_int;
}
break;
case TSW_long: // long double, long int
if (TypeSpecType != TST_unspecified && TypeSpecType != TST_int &&
TypeSpecType != TST_double) {
D.Report(Loc, diag::err_invalid_long_spec,
getSpecifierName(TypeSpecType));
TypeSpecType = TST_int;
}
}
return diag::NUM_DIAGNOSTICS;
}

View File

@ -28,7 +28,7 @@ using namespace clang;
/// [C99] function-specifier declaration-specifiers [opt]
/// [GNU] attributes declaration-specifiers [opt] [TODO]
///
/// storage-class-specifier: [C99 6.7.1]
/// storage-class-specifier: [C99 6.7.1] [TODO]
/// 'typedef'
/// 'extern'
/// 'static'
@ -73,9 +73,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
default:
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
diag::kind Res = DS.Finish(getLang());
if (Res != diag::NUM_DIAGNOSTICS)
Diag(StartLoc, Res);
DS.Finish(StartLoc, Diags, getLang());
return;
// type-specifiers
case tok::kw_short:

View File

@ -243,5 +243,13 @@ DIAG(ext_duplicate_declspec, EXTENSION,
DIAG(err_invalid_decl_spec_combination, ERROR,
"cannot combine declaration specifier with previous '%s' specifier")
DIAG(err_invalid_sign_spec, ERROR,
"'%s' cannot be signed or unsigned")
DIAG(err_invalid_short_spec, ERROR,
"'short %s' is invalid")
DIAG(err_invalid_long_spec, ERROR,
"'long %s' is invalid")
DIAG(err_invalid_longlong_spec, ERROR,
"'long long %s' is invalid")
#undef DIAG

View File

@ -19,6 +19,7 @@
namespace llvm {
namespace clang {
class LangOptions;
class SourceLocation;
/// DeclSpec - This class captures information about "declaration specifiers",
/// which encompases storage-class-specifiers, type-specifiers, type-qualifiers,
@ -121,11 +122,10 @@ public:
bool SetTypeQual(TQ T, const char *&PrevSpec, const LangOptions &Lang);
/// 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,
/// Finish - This does final analysis of the declspec, issuing diagnostics for
/// things like "_Imaginary" (lacking an FP type). After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
diag::kind Finish(const LangOptions &Lang);
void Finish(SourceLocation Loc, Diagnostic &D,const LangOptions &Lang);
};
} // end namespace clang