Emit diagnostics for things like 'signed _Bool' and 'short float'
llvm-svn: 38811
This commit is contained in:
parent
494f27a0b8
commit
839713c085
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "clang/Parse/Declarations.h"
|
#include "clang/Parse/Declarations.h"
|
||||||
#include "clang/Basic/LangOptions.h"
|
#include "clang/Basic/LangOptions.h"
|
||||||
|
#include "clang/Basic/SourceLocation.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
@ -67,19 +68,24 @@ static bool BadSpecifier(DeclSpec::TSS S, const char *&PrevSpec) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool BadSpecifier(DeclSpec::TST T, const char *&PrevSpec) {
|
static const char *getSpecifierName(DeclSpec::TST T) {
|
||||||
switch (T) {
|
switch (T) {
|
||||||
case DeclSpec::TST_unspecified: PrevSpec = "unspecified"; break;
|
default: assert(0 && "Unknown typespec!");
|
||||||
case DeclSpec::TST_void: PrevSpec = "void"; break;
|
case DeclSpec::TST_unspecified: return "unspecified";
|
||||||
case DeclSpec::TST_char: PrevSpec = "char"; break;
|
case DeclSpec::TST_void: return "void";
|
||||||
case DeclSpec::TST_int: PrevSpec = "int"; break;
|
case DeclSpec::TST_char: return "char";
|
||||||
case DeclSpec::TST_float: PrevSpec = "float"; break;
|
case DeclSpec::TST_int: return "int";
|
||||||
case DeclSpec::TST_double: PrevSpec = "double"; break;
|
case DeclSpec::TST_float: return "float";
|
||||||
case DeclSpec::TST_bool: PrevSpec = "_Bool"; break;
|
case DeclSpec::TST_double: return "double";
|
||||||
case DeclSpec::TST_decimal32: PrevSpec = "_Decimal32"; break;
|
case DeclSpec::TST_bool: return "_Bool";
|
||||||
case DeclSpec::TST_decimal64: PrevSpec = "_Decimal64"; break;
|
case DeclSpec::TST_decimal32: return "_Decimal32";
|
||||||
case DeclSpec::TST_decimal128: PrevSpec = "_Decimal128"; break;
|
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;
|
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
|
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
|
||||||
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
|
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
|
||||||
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
|
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
|
||||||
diag::kind DeclSpec::Finish(const LangOptions &Lang) {
|
void DeclSpec::Finish(SourceLocation Loc, Diagnostic &D,
|
||||||
// FIXME: implement this.
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ using namespace clang;
|
||||||
/// [C99] function-specifier declaration-specifiers [opt]
|
/// [C99] function-specifier declaration-specifiers [opt]
|
||||||
/// [GNU] attributes declaration-specifiers [opt] [TODO]
|
/// [GNU] attributes declaration-specifiers [opt] [TODO]
|
||||||
///
|
///
|
||||||
/// storage-class-specifier: [C99 6.7.1]
|
/// storage-class-specifier: [C99 6.7.1] [TODO]
|
||||||
/// 'typedef'
|
/// 'typedef'
|
||||||
/// 'extern'
|
/// 'extern'
|
||||||
/// 'static'
|
/// 'static'
|
||||||
|
@ -73,9 +73,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
|
||||||
default:
|
default:
|
||||||
// If this is not a declaration specifier token, we're done reading decl
|
// If this is not a declaration specifier token, we're done reading decl
|
||||||
// specifiers. First verify that DeclSpec's are consistent.
|
// specifiers. First verify that DeclSpec's are consistent.
|
||||||
diag::kind Res = DS.Finish(getLang());
|
DS.Finish(StartLoc, Diags, getLang());
|
||||||
if (Res != diag::NUM_DIAGNOSTICS)
|
|
||||||
Diag(StartLoc, Res);
|
|
||||||
return;
|
return;
|
||||||
// type-specifiers
|
// type-specifiers
|
||||||
case tok::kw_short:
|
case tok::kw_short:
|
||||||
|
|
|
@ -243,5 +243,13 @@ DIAG(ext_duplicate_declspec, EXTENSION,
|
||||||
|
|
||||||
DIAG(err_invalid_decl_spec_combination, ERROR,
|
DIAG(err_invalid_decl_spec_combination, ERROR,
|
||||||
"cannot combine declaration specifier with previous '%s' specifier")
|
"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
|
#undef DIAG
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class LangOptions;
|
class LangOptions;
|
||||||
|
class SourceLocation;
|
||||||
|
|
||||||
/// DeclSpec - This class captures information about "declaration specifiers",
|
/// DeclSpec - This class captures information about "declaration specifiers",
|
||||||
/// which encompases storage-class-specifiers, type-specifiers, type-qualifiers,
|
/// which encompases storage-class-specifiers, type-specifiers, type-qualifiers,
|
||||||
|
@ -121,11 +122,10 @@ public:
|
||||||
|
|
||||||
bool SetTypeQual(TQ T, const char *&PrevSpec, const LangOptions &Lang);
|
bool SetTypeQual(TQ T, const char *&PrevSpec, const LangOptions &Lang);
|
||||||
|
|
||||||
/// Finish - This does final analysis of the declspec, rejecting things like
|
/// Finish - This does final analysis of the declspec, issuing diagnostics for
|
||||||
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
|
/// things like "_Imaginary" (lacking an FP type). After calling this method,
|
||||||
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
|
|
||||||
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
|
/// 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
|
} // end namespace clang
|
||||||
|
|
Loading…
Reference in New Issue