Commit Graph

158 Commits

Author SHA1 Message Date
Douglas Gregor 97f1f1c46e The injected-class-name of class templates and class template
specializations can be treated as a template. Finally, we can parse
and process the first implementation of Fibonacci I wrote!

Note that this code does not handle all of the cases where
injected-class-names can be treated as templates. In particular,
there's an ambiguity case that we should be able to handle (but
can't), e.g.,

  template <class T> struct Base { }; 
  template <class T> struct Derived : Base<int>, Base<char> {
    typename Derived::Base b;       // error: ambiguous
    typename Derived::Base<double> d;  // OK 
  };

llvm-svn: 67720
2009-03-26 00:10:35 +00:00
Douglas Gregor c08f489d38 In Parser::ParseClassSpecifier, don't conflate a NULL declaration with
failure to perform a declaration. Instead, explicitly note semantic
failures that occur during template parsing with a DeclResult. Fixes
PR3872.

llvm-svn: 67659
2009-03-25 00:13:59 +00:00
Douglas Gregor 64259f5143 Type::isObjectType now implements the (more sensible) C++ definition
of "object type" rather than the C definition of "object type". The
difference is that C's "object type" excludes incomplete types such as

  struct X;

However, C's definition also makes it far too easy to use isObjectType
as a means to detect incomplete types when in fact we should use other
means (e.g., Sema::RequireCompleteType) that cope with C++ semantics,
including template instantiation.

I've already audited every use of isObjectType and isIncompleteType to
ensure that they are doing the right thing for both C and C++, so this
is patch does not change any functionality.

llvm-svn: 67648
2009-03-24 20:32:41 +00:00
Douglas Gregor c9a1a3b9d9 Fix a few isObjectTypes that really need to be isIncompleteOrObject
types; add another use of RequireCompleteType.

llvm-svn: 67644
2009-03-24 20:13:58 +00:00
Douglas Gregor 90a1a65194 Introduce a new expression type, UnresolvedDeclRefExpr, that describes
dependent qualified-ids such as

  Fibonacci<N - 1>::value

where N is a template parameter. These references are "unresolved"
because the name is dependent and, therefore, cannot be resolved to a
declaration node (as we would do for a DeclRefExpr or
QualifiedDeclRefExpr). UnresolvedDeclRefExprs instantiate to
DeclRefExprs, QualifiedDeclRefExprs, etc.

Also, be a bit more careful about keeping only a single set of
specializations for a class template, and instantiating from the
definition of that template rather than a previous declaration. In
general, we need a better solution for this for all TagDecls, because
it's too easy to accidentally look at a declaration that isn't the
definition.

We can now process a simple Fibonacci computation described as a
template metaprogram.

llvm-svn: 67308
2009-03-19 17:26:29 +00:00
Douglas Gregor e177b7254d Extend the use of QualifiedNameType to the creation of class template
specialization names. This way, we keep track of sugared types like

  std::vector<Real>

I believe we are now using QualifiedNameTypes everywhere we can. Next
step: QualifiedDeclRefExprs.

llvm-svn: 67268
2009-03-19 00:39:20 +00:00
Douglas Gregor 5253768ada 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 00:18:19 +00:00
Douglas Gregor 6bfde496ee The scope representation can now be either a DeclContext pointer or a
Type pointer. This allows our nested-name-specifiers to retain more
information about the actual spelling (e.g., which typedef did the
user name, or what exact template arguments were used in the
template-id?). It will also allow us to have dependent
nested-name-specifiers that don't map to any DeclContext.

llvm-svn: 67140
2009-03-18 00:36:05 +00:00
Douglas Gregor 52aba87df7 Check for overflow and signedness problems with template
arguments. Eliminates a FIXME.

llvm-svn: 66993
2009-03-14 00:20:21 +00:00
Douglas Gregor 69bd16d814 Make sure that the canonical representation of integral template arguments uses the bitwidth and signedness of the template parameter
llvm-svn: 66990
2009-03-14 00:03:48 +00:00
Douglas Gregor 0950e41b73 Implement template instantiation for several more kinds of expressions:
- C++ function casts, e.g., T(foo)
  - sizeof(), alignof()

More importantly, this allows us to verify that we're performing
overload resolution during template instantiation, with
argument-dependent lookup and the "cached" results of name lookup from
the template definition.

llvm-svn: 66947
2009-03-13 21:01:28 +00:00
Douglas Gregor b970d0ca9d Store the type of the integral value within a TemplateArgument, so that we can more efficiently reconstruct an IntegerLiteral from it during template instantiation
llvm-svn: 66833
2009-03-12 22:20:26 +00:00
Douglas Gregor 79cf603428 Extend the notion of active template instantiations to include the
context of a template-id for which we need to instantiate default
template arguments.

In the TextDiagnosticPrinter, don't suppress the caret diagnostic if
we are producing a non-note diagnostic that follows a note diagnostic
with the same location, because notes are (conceptually) a part of the
warning or error that comes before them.

llvm-svn: 66572
2009-03-10 20:44:00 +00:00
Douglas Gregor 65b2c4c381 Add pretty-printing for class template specializations, e.g.,
'struct A<double, int>'

In the "template instantiation depth exceeded" message, print
"-ftemplate-depth-N" rather than "-ftemplate-depth=N".

An unnamed tag type that is declared with a typedef, e.g., 

  typedef struct { int x, y; } Point;

can be used as a template argument. Allow this, and check that we get
sensible pretty-printing for such things.

llvm-svn: 66560
2009-03-10 18:33:27 +00:00
Douglas Gregor c40290e452 Implement template instantiation for ClassTemplateSpecializationTypes,
such as replacing 'T' in vector<T>. There are a few aspects to this:

  - Extend TemplateArgument to allow arbitrary expressions (an
    Expr*), and switch ClassTemplateSpecializationType to store
    TemplateArguments rather than it's own type-or-expression
    representation.

  - ClassTemplateSpecializationType can now store dependent types. In
    that case, the canonical type is another
    ClassTemplateSpecializationType (with default template arguments
    expanded) rather than a declaration (we don't build Decls for
    dependent types).

  - Split ActOnClassTemplateId into ActOnClassTemplateId (called from
    the parser) and CheckClassTemplateId (called from
    ActOnClassTemplateId and InstantiateType). They're smart enough to
    handle dependent types, now.

llvm-svn: 66509
2009-03-09 23:48:35 +00:00
Douglas Gregor ce0fc86f07 Mark a non-type template parameter invalid if there was a problem with its type
llvm-svn: 66422
2009-03-09 16:46:39 +00:00
Douglas Gregor 463421deb1 Implement the basics of implicit instantiation of class templates, in
response to attempts to diagnose an "incomplete" type. This will force
us to use DiagnoseIncompleteType more regularly (rather than looking at
isIncompleteType), but that's also a good thing.

Implicit instantiation is still very simplistic, and will create a new
definition for the class template specialization (as it should) but it
only actually instantiates the base classes and attaches
those. Actually instantiating class members will follow. 

Also, instantiate the types of non-type template parameters before
checking them,  allowing, e.g., 

  template<typename T, T Value> struct Constant; 
 
to work properly.

llvm-svn: 65924
2009-03-03 04:44:36 +00:00
Douglas Gregor 17c0d7bacf Implement template instantiation for pointer, reference, and (some)
array types. Semantic checking for the construction of these types has
been factored out of GetTypeForDeclarator and into separate
subroutines (BuildPointerType, BuildReferenceType,
BuildArrayType). We'll be doing the same thing for all other types
(and declarations and expressions).

As part of this, moved the type-instantiation functions into a class
in an anonymous namespace. 

llvm-svn: 65663
2009-02-28 00:25:32 +00:00
Douglas Gregor fe1e11092e Implement the basic approach for instantiating types, with a lot of FIXME'd
stubs for those types we don't yet know how to instantiate (everything
that isn't a template parameter!).

We now instantiate default arguments for template type parameters when
needed. This will be our testbed while I fill out the remaining
type-instantiation logic.

llvm-svn: 65649
2009-02-27 19:31:52 +00:00
Douglas Gregor 96977da72c Clean up and document code modification hints.
llvm-svn: 65641
2009-02-27 17:53:17 +00:00
Douglas Gregor d56a91e8f6 Make the type associated with a ClassTemplateSpecializationDecl be a
nicely sugared type that shows how the user wrote the actual
specialization. This sugared type won't actually show up until we
start doing instantiations.

llvm-svn: 65577
2009-02-26 22:19:44 +00:00
Douglas Gregor 87f95b0a6a Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:

  - Insert some new code (a text string) at a particular source
    location
  - Remove the code within a given range
  - Replace the code within a given range with some new code (a text
    string)

Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:

  template<int I> class B { };
  B<1000 >> 2> *b1;

we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:

test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
  B<1000 >> 2> *b1;
         ^
    (        )


Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.

In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.

This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).

llvm-svn: 65570
2009-02-26 21:00:50 +00:00
Douglas Gregor 1e249f8641 Improve location information on "reused" class template specialization
decls. Test and document the semantic location of class template
specialization definitions that occur within a scope enclosing the
scope of the class template.

llvm-svn: 65478
2009-02-25 22:18:32 +00:00
Douglas Gregor f47b911f6e Perform additional semantic checking of class template
specializations. In particular:

  - Make sure class template specializations have a "template<>"
    header, and complain if they don't.
  - Make sure class template specializations are declared/defined
    within a valid context. (e.g., you can't declare a specialization
    std::vector<MyType> in the global namespace).

llvm-svn: 65476
2009-02-25 22:02:03 +00:00
Douglas Gregor 7f74112756 Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type

When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:

  template<> class Outer::Inner<int> { ... };

We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.

Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.

llvm-svn: 65467
2009-02-25 19:37:18 +00:00
Chris Lattner 696197cd30 silence some warnings in no asserts mode.
llvm-svn: 65169
2009-02-20 21:37:53 +00:00
Douglas Gregor 171c45ab0c Downgrade complaints about calling unavailable functions to a warning
(as GCC does), except when we've performed overload resolution and
found an unavailable function: in this case, we actually error.

Merge the checking of unavailable functions with the checking for
deprecated functions. This unifies a bit of code, and makes sure that
we're checking for unavailable functions in the right places. Also,
this check can cause an error. We may, eventually, want an option to
make "unavailable" warnings into errors.

Implement much of the logic needed for C++0x deleted functions, which
are effectively the same as "unavailable" functions (but always cause
an error when referenced). However, we don't have the syntax to
specify deleted functions yet :)

llvm-svn: 64955
2009-02-18 21:56:37 +00:00
Douglas Gregor 67a6564091 Implement basic parsing and semantic analysis for explicit
specialization of class templates, e.g.,

  template<typename T> class X;

  template<> class X<int> { /* blah */ };

Each specialization is a different *Decl node (naturally), and can
have different members. We keep track of forward declarations and
definitions as for other class/struct/union types.

This is only the basic framework: we still have to deal with checking
the template headers properly, improving recovery when there are
failures, handling nested name specifiers, etc.

llvm-svn: 64848
2009-02-17 23:15:12 +00:00
Douglas Gregor 264ec4f237 Added ClassTemplateSpecializationDecl, which is a subclass of
CXXRecordDecl that is used to represent class template
specializations. These are canonical declarations that can refer to
either an actual class template specialization in the code, e.g.,

  template<> class vector<bool> { };

or to a template instantiation. However, neither of these features is
actually implemented yet, so really we're just using (and uniqing) the
declarations to make sure that, e.g., A<int> is a different type from
A<float>. Note that we carefully distinguish between what the user
wrote in the source code (e.g., "A<FLOAT>") and the semantic entity it
represents (e.g., "A<float, int>"); the former is in the sugared Type,
the latter is an actual Decl.

llvm-svn: 64716
2009-02-17 01:05:43 +00:00
Mike Stump c89c8e3225 Fix comment.
llvm-svn: 64337
2009-02-11 23:03:27 +00:00
Douglas Gregor 5bd22da927 Appease the language lawyers
llvm-svn: 64321
2009-02-11 20:46:19 +00:00
Douglas Gregor ccb0776288 Finished semantic analysis of non-type template arguments, to check
for non-external names whose address becomes the template
argument. This completes C++ [temp.arg.nontype]p1.

Note that our interpretation of C++ [temp.arg.nontype]p1b3 differs
from EDG's interpretation (we're stricter, and GCC agrees with
us). They're opening a core issue about the matter.

llvm-svn: 64317
2009-02-11 19:52:55 +00:00
Mike Stump 761b90b825 Avoid bogus warning.
llvm-svn: 64313
2009-02-11 18:58:46 +00:00
Douglas Gregor 1515f76a5a Reverted r64307. Moved hasSameType and hasSameUnqualifiedType from
Sema to ASTContext.

llvm-svn: 64312
2009-02-11 18:22:40 +00:00
Douglas Gregor f8f868336e Allow the use of default template arguments when forming a class
template specialization (e.g., std::vector<int> would now be
well-formed, since it relies on a default argument for the Allocator
template parameter). 

This is much less interesting than one might expect, since (1) we're
not actually using the default arguments for anything important, such
as naming an actual Decl, and (2) we'll often need to instantiate the
default arguments to check their well-formedness. The real fun will
come later.

llvm-svn: 64310
2009-02-11 18:16:40 +00:00
Douglas Gregor 0ada9f5d46 Rename Sema::hasSameType to QualType::isSameAs
Rename Sema::hasSameUnqualifiedType to QualType::isSameIgnoringQalifiers

llvm-svn: 64307
2009-02-11 16:47:37 +00:00
Douglas Gregor 0e55853639 Implement semantic checking for template arguments that correspond to
pointer-to-member-data non-type template parameters. Also, get
consistent about what it means to returned a bool from
CheckTemplateArgument.

llvm-svn: 64305
2009-02-11 16:16:59 +00:00
Douglas Gregor 6f233ef1d8 Add semantic checking for template arguments that correspond to
non-type template parameters that are references to functions or
pointers to member functions. Did a little bit of refactoring so that
these two cases, along with the handling of non-type template
parameters that are pointers to functions, are handled by the same
path. 

Also, tweaked FixOverloadedFunctionReference to cope with member
function pointers. This is a necessary step for getting all of the fun
member pointer conversions working outside of template arguments, too.

llvm-svn: 64277
2009-02-11 01:18:59 +00:00
Douglas Gregor a9faa44162 Semantic checking for template arguments that correspond to non-type
template parameters that have reference type. Effectively, we're doing
a very limited form of reference binding here.

llvm-svn: 64270
2009-02-11 00:44:29 +00:00
Douglas Gregor 3a7796bccc Add partial semantic checking of template arguments that are meant for
non-type template parameters of pointer-to-object and
pointer-to-function type. The most fun part of this is the use of
overload resolution to pick a function from the set of overloaded
functions that comes in as a template argument.

Also, fixed two minor bugs in this area:
  - We were allowing non-type template parameters of type pointer to
  void.
  - We weren't patching up an expression that refers to an overloaded
  function set via "&f" properly.

We're still not performing complete checking of the expression to be
sure that it is referring to an object or function with external
linkage (C++ [temp.arg.nontype]p1).

llvm-svn: 64266
2009-02-11 00:19:33 +00:00
Douglas Gregor 86560404fc Add type-checking and implicit conversions for template parameters of
integral or enumeration type.

llvm-svn: 64256
2009-02-10 23:36:10 +00:00
Douglas Gregor dba326363c Implement parsing, semantic analysis and ASTs for default template
arguments. This commit covers checking and merging default template
arguments from previous declarations, but it does not cover the actual
use of default template arguments when naming class template
specializations.

llvm-svn: 64229
2009-02-10 19:49:53 +00:00
Douglas Gregor 8133879c5e Semantic analysis for non-type template parameter declarations.
llvm-svn: 64223
2009-02-10 17:43:50 +00:00
Douglas Gregor 97f34576d4 Teach the type-id/expression disambiguator about different
disambiguation contexts, so that we properly parse template arguments
such as

  A<int()>

as type-ids rather than as expressions. Since this can be confusing
(especially when the template parameter is a non-type template
parameter), we try to give a friendly error message.

Almost, eliminate a redundant error message (that should have been a
note) and add some ultra-basic checks for non-type template
arguments.

llvm-svn: 64189
2009-02-10 00:53:15 +00:00
Douglas Gregor 85e0f66250 Check template template arguments against their corresponding template
template parameters.

llvm-svn: 64188
2009-02-10 00:24:35 +00:00
Douglas Gregor d32e028f79 Rudimentary checking of template arguments against their corresponding
template parameters when performing semantic analysis of a template-id
naming a class template specialization.

llvm-svn: 64185
2009-02-09 23:23:08 +00:00
Douglas Gregor 67b556a0da Eliminate TemplateArg so that we only have a single kind of
representation for template arguments. Also simplifies the interface
for ActOnClassTemplateSpecialization and eliminates some annoying
allocations of TemplateArgs.

My attempt at smart pointers for template arguments lists is
relatively lame. We can improve it once we're sure that we have the
right representation for template arguments.

llvm-svn: 64154
2009-02-09 19:34:22 +00:00
Douglas Gregor 8bf4205c70 Start processing template-ids as types when the template-name refers
to a class template. For example, the template-id 'vector<int>' now
has a nice, sugary type in the type system. What we can do now:

  - Parse template-ids like 'vector<int>' (where 'vector' names a
    class template) and form proper types for them in the type system.
  - Parse icky template-ids like 'A<5>' and 'A<(5 > 0)>' properly,
    using (sadly) a bool in the parser to tell it whether '>' should
    be treated as an operator or not.

This is a baby-step, with major problems and limitations:
  - There are currently two ways that we handle template arguments
  (whether they are types or expressions). These will be merged, and,
  most likely, TemplateArg will disappear.
  - We don't have any notion of the declaration of class template
  specializations or of template instantiations, so all template-ids
  are fancy names for 'int' :)

llvm-svn: 64153
2009-02-09 18:46:07 +00:00
Douglas Gregor cd72ba97e7 Semantic checking for class template declarations and
redeclarations. For example, checks that a class template
redeclaration has the same template parameters as previous
declarations.

Detangled class-template checking from ActOnTag, whose logic was
getting rather convoluted because it tried to handle C, C++, and C++
template semantics in one shot.

Made some inroads toward eliminating extraneous "declaration does not
declare anything" errors by adding an "error" type specifier.

llvm-svn: 63973
2009-02-06 22:42:48 +00:00
Douglas Gregor ded2d7b021 Basic representation of C++ class templates, from Andrew Sutton.
llvm-svn: 63750
2009-02-04 19:02:06 +00:00
Douglas Gregor 2ada048975 Some name-lookup-related fixes, from Piotr Rak!
- Changes Lookup*Name functions to return NamedDecls, instead of
Decls. Unfortunately my recent statement that it will simplify lot of
code, was not quite right, but it simplifies some...
- Makes MergeLookupResult SmallPtrSet instead of vector, following
Douglas suggestions.
- Adds %qN format for printing qualified names to Diagnostic.
- Avoids searching for using-directives in Scopes, which are not
DeclScope, during unqualified name lookup.

llvm-svn: 63739
2009-02-04 17:27:36 +00:00
Douglas Gregor ed8f288708 Eliminated LookupCriteria, whose creation was causing a bottleneck for
LookupName et al. Instead, use an enum and a bool to describe its
contents.

Optimized the C/Objective-C path through LookupName, eliminating any
unnecessarily C++isms. Simplify IdentifierResolver::iterator, removing
some code and arguments that are no longer used.

Eliminated LookupDeclInScope/LookupDeclInContext, moving all callers
over to LookupName, LookupQualifiedName, or LookupParsedName, as
appropriate.

All together, I'm seeing a 0.2% speedup on Cocoa.h with PTH and
-disable-free. Plus, we're down to three name-lookup routines.

llvm-svn: 63354
2009-01-30 01:04:22 +00:00
Steve Naroff dcfe56d489 Refactor Sema::LookupDecl() into 2 functions: LookupDeclInScope() and LookupDeclInContext().
The previous interface was very confusing. This is much more explicit, which will be easier to understand/optimize/convert.

The plan is to eventually deprecate both of these functions. For now, I'm focused on performance.

llvm-svn: 63256
2009-01-29 00:07:50 +00:00
Douglas Gregor b9bd8a994c Keep track of template arguments when we parse them. Right now, we don't actually do anything with the template arguments, but they'll be used to create template declarations
llvm-svn: 61413
2008-12-24 02:52:09 +00:00
Douglas Gregor 55ad91fecb Ultrasimplistic sketch for the parsing of C++ template-ids. This won't
become useful or correct until we (1) parse template arguments
correctly, (2) have some way to turn template-ids into types,
declarators, etc., and (3) have a real representation of templates.

llvm-svn: 61208
2008-12-18 19:37:40 +00:00
Douglas Gregor 5daeee2bd6 Move Sema::isTemplateParameterDecl to Decl::isTemplateParameter, where it belongs
llvm-svn: 60708
2008-12-08 18:40:42 +00:00
Douglas Gregor 4619e439b6 Introduce basic support for dependent types, type-dependent
expressions, and value-dependent expressions. This permits us to parse
some template definitions.

This is not a complete solution; we're missing type- and
value-dependent computations for most of the expression types, and
we're missing checks for dependent types and type-dependent
expressions throughout Sema.

llvm-svn: 60615
2008-12-05 23:32:09 +00:00
Douglas Gregor 5101c24f60 Representation of template type parameters and non-type template
parameters, with some semantic analysis:
  - Template parameters are introduced into template parameter scope
  - Complain about template parameter shadowing (except in Microsoft mode)

Note that we leak template parameter declarations like crazy, a
problem we'll remedy once we actually create proper declarations for
templates. 

Next up: dependent types and value-dependent/type-dependent
expressions.

llvm-svn: 60597
2008-12-05 18:15:24 +00:00