/// 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. void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); // Check the type specifier components first. // If decltype(auto) is used, no other type specifiers are permitted. if (TypeSpecType == TST_decltype_auto && (TypeSpecWidth != TSW_unspecified || TypeSpecComplex != TSC_unspecified || TypeSpecSign != TSS_unspecified || TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || TypeQualifiers)) { const unsigned NumLocs = 9; SourceLocation ExtraLocs[NumLocs] = { TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc }; FixItHint Hints[NumLocs]; SourceLocation FirstLoc; for (unsigned I = 0; I != NumLocs; ++I) { if (ExtraLocs[I].isValid()) { if (FirstLoc.isInvalid() || S.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I], FirstLoc)) FirstLoc = ExtraLocs[I]; Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]); } } TypeSpecWidth = TSW_unspecified; TypeSpecComplex = TSC_unspecified; TypeSpecSign = TSS_unspecified; TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false; TypeQualifiers = 0; S.Diag(TSTLoc, diag::err_decltype_auto_cannot_be_combined) << Hints[0] << Hints[1] << Hints[2] << Hints[3] << Hints[4] << Hints[5] << Hints[6] << Hints[7]; } // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { S.Diag(TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { S.Diag(TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType, Policy)); } // Only 'short' and 'long long' are valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) && (TypeSpecWidth != TSW_longlong)) S.Diag(TSWLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // vector bool long long requires VSX support or ZVector. if ((TypeSpecWidth == TSW_longlong) && (!S.Context.getTargetInfo().hasFeature("vsx")) && (!S.Context.getTargetInfo().hasFeature("power8-vector")) && !S.getLangOpts().ZVector) S.Diag(TSTLoc, diag::err_invalid_vector_long_long_decl_spec); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } else if (TypeSpecType == TST_double) { // vector long double and vector long long double are never allowed. // vector double is OK for Power7 and later, and ZVector. if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong) S.Diag(TSWLoc, diag::err_invalid_vector_long_double_decl_spec); else if (!S.Context.getTargetInfo().hasFeature("vsx") && !S.getLangOpts().ZVector) S.Diag(TSTLoc, diag::err_invalid_vector_double_decl_spec); } else if (TypeSpecType == TST_float) { // vector float is unsupported for ZVector. if (S.getLangOpts().ZVector) S.Diag(TSTLoc, diag::err_invalid_vector_float_decl_spec); } else if (TypeSpecWidth == TSW_long) { // vector long is unsupported for ZVector and deprecated for AltiVec. if (S.getLangOpts().ZVector) S.Diag(TSWLoc, diag::err_invalid_vector_long_decl_spec); else S.Diag(TSWLoc, diag::warn_vector_long_decl_spec_combination) << getSpecifierName((TST)TypeSpecType, Policy); } if (TypeAltiVecPixel) { //TODO: perform validation TypeSpecType = TST_int; TypeSpecSign = TSS_unsigned; TypeSpecWidth = TSW_short; TypeSpecOwned = false; } } // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { S.Diag(TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType, Policy); // signed double -> double. 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; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { S.Diag(TSWLoc, diag::err_invalid_width_spec) << (int)TypeSpecWidth << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { S.Diag(TSWLoc, diag::err_invalid_width_spec) << (int)TypeSpecWidth << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { S.Diag(TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion( S.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. if (!S.getLangOpts().CPlusPlus) S.Diag(TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { S.Diag(TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecComplex = TSC_unspecified; } } // C11 6.7.1/3, C++11 [dcl.stc]p1, GNU TLS: __thread, thread_local and // _Thread_local can only appear with the 'static' and 'extern' storage class // specifiers. We also allow __private_extern__ as an extension. if (ThreadStorageClassSpec != TSCS_unspecified) { switch (StorageClassSpec) { case SCS_unspecified: case SCS_extern: case SCS_private_extern: case SCS_static: break; default: if (S.getSourceManager().isBeforeInTranslationUnit( getThreadStorageClassSpecLoc(), getStorageClassSpecLoc())) S.Diag(getStorageClassSpecLoc(), diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getThreadStorageClassSpec()) << SourceRange(getThreadStorageClassSpecLoc()); else S.Diag(getThreadStorageClassSpecLoc(), diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getStorageClassSpec()) << SourceRange(getStorageClassSpecLoc()); // Discard the thread storage class specifier to recover. ThreadStorageClassSpec = TSCS_unspecified; ThreadStorageClassSpecLoc = SourceLocation(); } } // If no type specifier was provided and we're parsing a language where // the type specifier is not optional, but we got 'auto' as a storage // class specifier, then assume this is an attempt to use C++0x's 'auto' // type specifier. if (S.getLangOpts().CPlusPlus && TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { TypeSpecType = TST_auto; StorageClassSpec = SCS_unspecified; TSTLoc = TSTNameLoc = StorageClassSpecLoc; StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class // specifier in a pre-C++11 dialect of C++. if (!S.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) S.Diag(TSTLoc, diag::ext_auto_type_specifier); if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) S.Diag(StorageClassSpecLoc, diag::warn_auto_storage_class) << FixItHint::CreateRemoval(StorageClassSpecLoc); if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32) S.Diag(TSTLoc, diag::warn_cxx98_compat_unicode_type) << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t"); if (Constexpr_specified) S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr); // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && (getStorageClassSpec() || getThreadStorageClassSpec())) { SmallString<32> SpecName; SourceLocation SCLoc; FixItHint StorageHint, ThreadHint; if (DeclSpec::SCS SC = getStorageClassSpec()) { SpecName = getSpecifierName(SC); SCLoc = getStorageClassSpecLoc(); StorageHint = FixItHint::CreateRemoval(SCLoc); } if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) { if (!SpecName.empty()) SpecName += " "; SpecName += getSpecifierName(TSC); SCLoc = getThreadStorageClassSpecLoc(); ThreadHint = FixItHint::CreateRemoval(SCLoc); } S.Diag(SCLoc, diag::err_friend_decl_spec) << SpecName << StorageHint << ThreadHint; ClearStorageClassSpecs(); } // C++11 [dcl.fct.spec]p5: // The virtual specifier shall be used only in the initial // declaration of a non-static class member function; // C++11 [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of // a constructor or conversion function within its class // definition; if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) { StringRef Keyword; SourceLocation SCLoc; if (isVirtualSpecified()) { Keyword = "virtual"; SCLoc = getVirtualSpecLoc(); } else { Keyword = "explicit"; SCLoc = getExplicitSpecLoc(); } FixItHint Hint = FixItHint::CreateRemoval(SCLoc); S.Diag(SCLoc, diag::err_friend_decl_spec) << Keyword << Hint; FS_virtual_specified = FS_explicit_specified = false; FS_virtualLoc = FS_explicitLoc = SourceLocation(); } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }