diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 37 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 58 |
2 files changed, 65 insertions, 30 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 277a67f..c3c56dd 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2192,7 +2192,22 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } }; - // Inform the current actions module that we just parsed this declarator. + enum class InitKind { Uninitialized, Equal, CXXDirect, CXXBraced }; + InitKind TheInitKind; + // If a '==' or '+=' is found, suggest a fixit to '='. + if (isTokenEqualOrEqualTypo()) + TheInitKind = InitKind::Equal; + else if (Tok.is(tok::l_paren)) + TheInitKind = InitKind::CXXDirect; + else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) && + (!CurParsedObjCImpl || !D.isFunctionDeclarator())) + TheInitKind = InitKind::CXXBraced; + else + TheInitKind = InitKind::Uninitialized; + if (TheInitKind != InitKind::Uninitialized) + D.setHasInitializer(); + + // Inform Sema that we just parsed this declarator. Decl *ThisDecl = nullptr; Decl *OuterDecl = nullptr; switch (TemplateInfo.Kind) { @@ -2254,9 +2269,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } } + switch (TheInitKind) { // Parse declarator '=' initializer. - // If a '==' or '+=' is found, suggest a fixit to '='. - if (isTokenEqualOrEqualTypo()) { + case InitKind::Equal: { SourceLocation EqualLoc = ConsumeToken(); if (Tok.is(tok::kw_delete)) { @@ -2311,7 +2326,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Actions.AddInitializerToDecl(ThisDecl, Init.get(), /*DirectInit=*/false); } - } else if (Tok.is(tok::l_paren)) { + break; + } + case InitKind::CXXDirect: { // Parse C++ direct initializer: '(' expression-list ')' BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -2365,8 +2382,9 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Actions.AddInitializerToDecl(ThisDecl, Initializer.get(), /*DirectInit=*/true); } - } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) && - (!CurParsedObjCImpl || !D.isFunctionDeclarator())) { + break; + } + case InitKind::CXXBraced: { // Parse C++0x braced-init-list. Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); @@ -2381,9 +2399,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.get(), /*DirectInit=*/true); - - } else { + break; + } + case InitKind::Uninitialized: { Actions.ActOnUninitializedDecl(ThisDecl); + break; + } } Actions.FinalizeDeclaration(ThisDecl); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6da530c..dc11dac 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6023,6 +6023,31 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, return FixedTInfo; } +/// Attempt to fold a variable-sized type to a constant-sized type, returning +/// true if we were successful. +static bool tryToFixVariablyModifiedVarType(Sema &S, TypeSourceInfo *&TInfo, + QualType &T, SourceLocation Loc, + unsigned FailedFoldDiagID) { + bool SizeIsNegative; + llvm::APSInt Oversized; + TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo( + TInfo, S.Context, SizeIsNegative, Oversized); + if (FixedTInfo) { + S.Diag(Loc, diag::ext_vla_folded_to_constant); + TInfo = FixedTInfo; + T = FixedTInfo->getType(); + return true; + } + + if (SizeIsNegative) + S.Diag(Loc, diag::err_typecheck_negative_array_size); + else if (Oversized.getBoolValue()) + S.Diag(Loc, diag::err_array_too_large) << Oversized.toString(10); + else if (FailedFoldDiagID) + S.Diag(Loc, FailedFoldDiagID); + return false; +} + /// Register the given locally-scoped extern "C" declaration so /// that it can be found later for redeclarations. We include any extern "C" /// declaration that is not visible in the translation unit here, not just @@ -6861,6 +6886,12 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + // If this variable has a variable-modified type and an initializer, try to + // fold to a constant-sized type. This is otherwise invalid. + if (D.hasInitializer() && R->isVariablyModifiedType()) + tryToFixVariablyModifiedVarType(*this, TInfo, R, D.getIdentifierLoc(), + /*DiagID=*/0); + bool IsMemberSpecialization = false; bool IsVariableTemplateSpecialization = false; bool IsPartialSpecialization = false; @@ -16658,27 +16689,9 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (!InvalidDecl && T->isVariablyModifiedType()) { - bool SizeIsNegative; - llvm::APSInt Oversized; - - TypeSourceInfo *FixedTInfo = - TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, - SizeIsNegative, - Oversized); - if (FixedTInfo) { - Diag(Loc, diag::ext_vla_folded_to_constant); - TInfo = FixedTInfo; - T = FixedTInfo->getType(); - } else { - if (SizeIsNegative) - Diag(Loc, diag::err_typecheck_negative_array_size); - else if (Oversized.getBoolValue()) - Diag(Loc, diag::err_array_too_large) - << Oversized.toString(10); - else - Diag(Loc, diag::err_typecheck_field_variable_size); + if (!tryToFixVariablyModifiedVarType( + *this, TInfo, T, Loc, diag::err_typecheck_field_variable_size)) InvalidDecl = true; - } } // Fields can not have abstract class types @@ -16904,8 +16917,9 @@ Decl *Sema::ActOnIvar(Scope *S, // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. else if (T->isVariablyModifiedType()) { - Diag(Loc, diag::err_typecheck_ivar_variable_size); - D.setInvalidType(); + if (!tryToFixVariablyModifiedVarType( + *this, TInfo, T, Loc, diag::err_typecheck_ivar_variable_size)) + D.setInvalidType(); } // Get the visibility (access control) for this ivar. |